diff -urN /usr/local/dmd/src/phobos/internal/backtrace_win32.d phobos/internal/backtrace_win32.d --- /usr/local/dmd/src/phobos/internal/backtrace_win32.d 1970-01-01 09:00:00.000000000 +0900 +++ phobos/internal/backtrace_win32.d 2006-12-09 23:56:23.000000000 +0900 @@ -0,0 +1,20 @@ +private void _d_save_backtrace_ebp(Exception e, void** p) { + while (p) { + e.backtrace ~= *(cast(void**)p+1); + p = cast(void**)*cast(void**)p; + if (e.backtrace.length > 100) break; + } +} + +extern (C) void _d_save_backtrace(Object o, void** p) { + Exception e = cast(Exception)o; + if (!e) return; + _d_save_backtrace_ebp(e, p); +} + +extern (C) void _d_save_backtrace_se(Object o, void* eip, void* ebp) { + Exception e = cast(Exception)o; + if (!e) return; + e.backtrace ~= eip; + _d_save_backtrace_ebp(e, cast(void**)ebp); +} diff -urN /usr/local/dmd/src/phobos/internal/deh.c phobos/internal/deh.c --- /usr/local/dmd/src/phobos/internal/deh.c 2006-12-03 17:19:34.000000000 +0900 +++ phobos/internal/deh.c 2006-12-10 00:38:14.000000000 +0900 @@ -87,9 +87,40 @@ #define STATUS_DIGITAL_MARS_D_EXCEPTION MAKE_EXCEPTION_CODE(3,'D',1) -Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record); + +typedef struct { + DWORD ContextFlags; + DWORD Dr0; + DWORD Dr1; + DWORD Dr2; + DWORD Dr3; + DWORD Dr6; + DWORD Dr7; + FLOATING_SAVE_AREA FloatSave; + DWORD SegGs; + DWORD SegFs; + DWORD SegEs; + DWORD SegDs; + DWORD Edi; + DWORD Esi; + DWORD Ebx; + DWORD Edx; + DWORD Ecx; + DWORD Eax; + DWORD Ebp; + DWORD Eip; + DWORD SegCs; // MUST BE SANITIZED + DWORD EFlags; // MUST BE SANITIZED + DWORD Esp; + DWORD SegSs; +// BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; +} CONTEXT_X86; + +Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record, CONTEXT_X86 *context); void __cdecl _d_local_unwind(struct DHandlerTable *handler_table, struct DEstablisherFrame *frame, int stop_index); +void _d_save_backtrace(Object *h, DWORD ebp); +void _d_save_backtrace_se(Object *h, DWORD eip, DWORD ebp); /*********************************** * The frame handler, this is called for each frame that has been registered @@ -158,7 +189,7 @@ { // Matched the catch type, so we've found the handler. int regebp; - pti = _d_translate_se_to_d_exception(exception_record); + pti = _d_translate_se_to_d_exception(exception_record, *(CONTEXT_X86 **)&context); // Initialize catch variable regebp = (int)&frame->ebp; // EBP for this frame @@ -206,7 +237,7 @@ int retval, Object **exception_object) { - *exception_object = _d_translate_se_to_d_exception(eptrs->ExceptionRecord); + *exception_object = _d_translate_se_to_d_exception(eptrs->ExceptionRecord, NULL); return retval; } @@ -216,8 +247,10 @@ void __stdcall _d_throw(Object *h) { - //printf("_d_throw(h = %p, &h = %p)\n", h, &h); - //printf("\tvptr = %p\n", *(void **)h); + DWORD ebp; + ebp = _EBP; + _d_save_backtrace(h, ebp); + RaiseException(STATUS_DIGITAL_MARS_D_EXCEPTION, EXCEPTION_NONCONTINUABLE, 1, (DWORD *)&h); @@ -246,7 +279,7 @@ * Converts a Windows Structured Exception code to a D Exception Object. */ -Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record) +Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record, CONTEXT_X86 *context) { Object *pti; @@ -258,23 +291,28 @@ case STATUS_INTEGER_DIVIDE_BY_ZERO: pti = _d_create_exception_object(&_Class_9Exception, "Integer Divide by Zero"); + if (context) _d_save_backtrace_se(pti, context->Eip, context->Ebp); break; case STATUS_FLOAT_DIVIDE_BY_ZERO: pti = _d_create_exception_object(&_Class_9Exception, "Float Divide by Zero"); + if (context) _d_save_backtrace_se(pti, context->Eip, context->Ebp); break; case STATUS_ACCESS_VIOLATION: pti = _d_create_exception_object(&_Class_9Exception, "Access Violation"); + if (context) _d_save_backtrace_se(pti, context->Eip, context->Ebp); break; case STATUS_STACK_OVERFLOW: pti = _d_create_exception_object(&_Class_9Exception, "Stack Overflow"); + if (context) _d_save_backtrace_se(pti, context->Eip, context->Ebp); break; // convert all other exception codes into a Win32Exception default: pti = _d_create_exception_object(&_Class_9Exception, "Win32 Exception"); + if (context) _d_save_backtrace_se(pti, context->Eip, context->Ebp); break; } diff -urN /usr/local/dmd/src/phobos/internal/deh2.d phobos/internal/deh2.d --- /usr/local/dmd/src/phobos/internal/deh2.d 2006-12-03 17:19:34.000000000 +0900 +++ phobos/internal/deh2.d 2006-12-09 21:03:31.000000000 +0900 @@ -26,6 +26,7 @@ //debug=1; import std.c.linux.linuxextern; +import std.string; extern (C) int _d_isbaseof(ClassInfo oc, ClassInfo c); @@ -83,6 +84,64 @@ } } +extern (C) { + struct sigval_t { + int sigval_int; + void *sigval_ptr; + } + struct siginfo_t { + int si_signo; /* Signal number */ + int si_errno; /* An errno value */ + int si_code; /* Signal code */ + int si_pid; /* Sending process ID */ + uint si_uid; /* Real user ID of sending process */ + int si_status; /* Exit value or signal */ + int si_utime; /* User time consumed */ + int si_stime; /* System time consumed */ + sigval_t si_value; /* Signal value */ + int si_int; /* POSIX.1b signal */ + void * si_ptr; /* POSIX.1b signal */ + void * si_addr; /* Memory location which caused fault */ + int si_band; /* Band event */ + int si_fd; /* File descriptor */ + } + struct mcontext_t { + uint[19] gregs; + /* Due to Linux's history we have to use a pointer here. The SysV/i386 + ABI requires a struct with the values. */ + /* + fpregset_t fpregs; + uint oldmask; + uint cr2; + */ + } + struct stack_t { + void *ss_sp; + int ss_flags; + uint ss_size; + } + struct ucontext_t { + uint uc_flags; + ucontext_t *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + // __sigset_t uc_sigmask; + // struct _libc_fpstate __fpregs_mem; + } + enum REG { + GS, FS, ES, DS, EDI, ESI, EBP, ESP, + EBX, EDX, ECX, EAX, TRAPNO, ERR, EIP, CS, EFL, UESP, SS + } + + char *strsignal(int id); + void __backtrace_handler(int id, siginfo_t *si, ucontext_t *uc) { + char *signame = strsignal(id); + Exception e = new Exception(toString(signame)); + e.backtrace ~= cast(void*)uc.uc_mcontext.gregs[REG.EIP]; + throw e; + } +} + /******************************************* * Given address that is inside a function, * figure out which function it is in. @@ -161,6 +220,13 @@ mov regebp,EBP ; } + Exception exception = cast(Exception)h; + int ignore_count; + // dirty, it seems to be from signal handler + if (exception && exception.backtrace) { + ignore_count = 2; + } + //static uint abc; //if (++abc == 2) *(char *)0=0; @@ -179,6 +245,15 @@ int ndx; int prev_ndx; + if (exception) { + if (!ignore_count) { + exception.backtrace ~= *(cast(void**)regebp+1); + } + else { + ignore_count--; + } + } + regebp = __eh_find_caller(regebp,&retaddr); if (!regebp) { // if end of call chain diff -urN /usr/local/dmd/src/phobos/internal/dmain2.d phobos/internal/dmain2.d --- /usr/local/dmd/src/phobos/internal/dmain2.d 2006-12-03 17:19:34.000000000 +0900 +++ phobos/internal/dmain2.d 2006-12-09 22:59:47.000000000 +0900 @@ -9,6 +9,9 @@ import std.c.string; import std.c.stdlib; import std.string; +import std.file; +import std.path; +import std.symtable; extern (C) void _STI_monitor_staticctor(); extern (C) void _STD_monitor_staticdtor(); @@ -23,6 +26,30 @@ extern (C) bool no_catch_exceptions; +version (linux) { + extern (C) { + struct sigaction_t { + union { + void *sa_handler; + void *sa_sigaction; + } + uint[32] sa_mask; + int sa_flags; + void *sa_restorer; + } + int sigaction(int signum, sigaction_t *act, sigaction_t *oldact); + extern (C) void __backtrace_handler(int id, void *si, void *uc); + const int SA_NOCLDSTOP = 1; + const int SA_NOCLDWAIT = 2; + const int SA_SIGINFO = 4; + const int SA_ONSTACK = 0x08000000; + const int SA_RESTART = 0x10000000; + const int SA_NODEFER = 0x40000000; + const int SA_RESETHAND = 0x80000000; + const int SA_INTERRUPT = 0x20000000; + } +} + /*********************************** * The D main() function supplied by the user's program */ @@ -51,13 +78,26 @@ am = cast(char[] *) malloc(argc * (char[]).sizeof); // BUG: alloca() conflicts with try-catch-finally stack unwinding //am = (char[] *) alloca(argc * (char[]).sizeof); + + sigaction_t sa; + sa.sa_sigaction = &__backtrace_handler; + sa.sa_flags = SA_SIGINFO; + sigaction(1, &sa, null); + sigaction(2, &sa, null); + sigaction(3, &sa, null); + sigaction(4, &sa, null); + sigaction(6, &sa, null); + sigaction(8, &sa, null); + sigaction(11, &sa, null); + sigaction(13, &sa, null); + sigaction(15, &sa, null); } version (Win32) { gc_init(); _minit(); - am = cast(char[] *) alloca(argc * (char[]).sizeof); - } + am = cast(char[] *) malloc(argc * (char[]).sizeof); + } if (no_catch_exceptions) { @@ -98,7 +138,37 @@ catch (Object o) { printf("Error: "); - o.print(); + Exception e = cast(Exception)o; + if (e) { + if (Symtable.getDefaultSymtable()) { + e.print(Symtable.getDefaultSymtable()); + exit(EXIT_FAILURE); + } + version (linux) { + char[] nmfile = addExt(args[0], "nm"); + if (exists(nmfile)) { + Symtable st = + new Symtable(nmfile, SymtableType.BINUTILS_NM); + e.print(st); + exit(EXIT_FAILURE); + } + } + version (Win32) { + char[] mapfile = addExt(args[0], "map"); + if (exists(mapfile)) { + Symtable st = + new Symtable(mapfile, SymtableType.DMC_MAP); + e.print(st); + exit(EXIT_FAILURE); + } + } + Symtable st = new Symtable("", SymtableType.NONE); + e.print(st); + exit(EXIT_FAILURE); + } + else { + o.print(); + } exit(EXIT_FAILURE); } } diff -urN /usr/local/dmd/src/phobos/internal/object.d phobos/internal/object.d --- /usr/local/dmd/src/phobos/internal/object.d 2006-12-03 17:19:34.000000000 +0900 +++ phobos/internal/object.d 2006-12-09 22:19:57.000000000 +0900 @@ -880,12 +880,15 @@ } } +import std.symtable; + /** * All recoverable exceptions should be derived from class Exception. */ class Exception : Object { char[] msg; + void*[] backtrace; /** * Constructor; msg is a descriptive message for the exception. @@ -900,7 +903,26 @@ printf("%.*s\n", toString()); } - char[] toString() { return msg; } + void print(Object sto) { + Symtable st = cast(Symtable)sto; + print(); + if (st && backtrace) { + printf("Backtrace:\n"); + foreach (addr; backtrace) { + char[] name = st.lookupName(cast(uint)addr); + if (name) { + printf("%08x %.*s\n", addr, name); + } + else { + printf("%08x ???\n", addr, name); + } + } + } + } + + char[] toString() { + return msg; + } } /** diff -urN /usr/local/dmd/src/phobos/linux.mak phobos/linux.mak --- /usr/local/dmd/src/phobos/linux.mak 2006-12-03 17:19:34.000000000 +0900 +++ phobos/linux.mak 2006-12-09 19:49:26.000000000 +0900 @@ -58,7 +58,7 @@ socket.o socketstream.o stdarg.o stdio.o format.o \ perf.o openrj.o uni.o trace.o boxer.o \ demangle.o cover.o bitarray.o bind.o aApplyR.o \ - signals.o cpuid.o traits.o typetuple.o \ + signals.o symtable.o cpuid.o traits.o typetuple.o \ ti_wchar.o ti_uint.o ti_short.o ti_ushort.o \ ti_byte.o ti_ubyte.o ti_long.o ti_ulong.o ti_ptr.o \ ti_float.o ti_double.o ti_real.o ti_delegate.o \ @@ -94,7 +94,8 @@ std/socket.d std/socketstream.d std/loader.d std/stdarg.d \ std/stdio.d std/format.d std/perf.d std/openrj.d std/uni.d \ std/boxer.d std/cstream.d std/demangle.d std/cover.d std/bitarray.d \ - std/signals.d std/cpuid.d std/typetuple.d std/traits.d std/bind.d + std/signals.d std/cpuid.d std/typetuple.d std/traits.d std/bind.d \ + std/symtable.d SRC_STD_C= std/c/process.d std/c/stdlib.d std/c/time.d std/c/stdio.d \ std/c/math.d std/c/stdarg.d std/c/stddef.d std/c/fenv.d std/c/string.d \ @@ -418,6 +419,9 @@ syserror.o : std/syserror.d $(DMD) -c $(DFLAGS) std/syserror.d +symtable.o : std/symtable.d + $(DMD) -c $(DFLAGS) std/symtable.d + thread.o : std/thread.d $(DMD) -c $(DFLAGS) std/thread.d diff -urN /usr/local/dmd/src/phobos/object.d phobos/object.d --- /usr/local/dmd/src/phobos/object.d 2006-12-03 17:19:34.000000000 +0900 +++ phobos/object.d 2006-12-09 19:47:17.000000000 +0900 @@ -129,9 +129,11 @@ class Exception : Object { char[] msg; + void*[] backtrace; this(char[] msg); void print(); + void print(Object st); char[] toString(); } diff -urN /usr/local/dmd/src/phobos/std/symtable.d phobos/std/symtable.d --- /usr/local/dmd/src/phobos/std/symtable.d 1970-01-01 09:00:00.000000000 +0900 +++ phobos/std/symtable.d 2006-12-09 22:42:59.000000000 +0900 @@ -0,0 +1,89 @@ +module std.symtable; + +import std.string; +import std.demangle; +import std.file; +import std.regexp; + +private { + extern (C) int strtol(char* ptr, char** eptr, int base); +} + +enum SymtableType { + NONE, BINUTILS_NM, DMC_MAP +} + +class Symtable { + class Sym { + uint addr; + char[] name; + this(uint a, char[] n) { + addr = a; + name = n; + } + int opCmp(Object o) { + return addr - (cast(Sym)o).addr; + } + } + + this(char[] filename, SymtableType st) { + switch (st) { + case SymtableType.BINUTILS_NM: + char[] cont = cast(char[])std.file.read(filename); + foreach (char[] line; std.string.split(cont, "\n")) { + char[][] toks = std.string.split(line, " "); + if (toks.length != 3) continue; + uint addr = strtol(toStringz(toks[0]), null, 16); + char[] name = demangle(toks[2]); + syms ~= new Sym(addr, name); + } + syms.sort; + break; + case SymtableType.DMC_MAP: + char[] cont = cast(char[])std.file.read(filename); + RegExp reg = + new RegExp(` [\dABCDEF]{4}:[\dABCDEF]{8}\s{7}(.*)`, ``); + foreach (char[] line; std.string.split(cont, "\n")) { + if (reg.test(line) == 0) continue; + line = reg.replace(`$1`); + char[][] toks = std.string.split(line); + if (toks.length != 2) continue; + uint addr = strtol(toStringz(toks[1]), null, 16); + char[] name = demangle(toks[0]); + syms ~= new Sym(addr, name); + } + syms.sort; + break; + case SymtableType.NONE: + break; + default: + throw new Error("unknown symtable type"); + } + } + + char[] lookupName(uint addr) { + for (int i = 0; i < syms.length; i++) { + if (syms[i].addr > addr) { + if (i == 0) return null; + else return syms[i-1].name; + } + } + return null; + } + + Sym[] getAllSymbol() { return syms; } + + static void setDefaultSymtable(Symtable st) { + default_symtable = st; + } + static Symtable getDefaultSymtable() { + return default_symtable; + } + +protected: + this() {} + +private: + Sym[] syms; + static Symtable default_symtable; +}