Created attachment 22548 [details] http://pastebin.com/XrxW7Jsm - Unwinding for MinGW(64) I asked Kai about unwinding support for MinGW64 - he has then posted the following link: http://pastebin.com/XrxW7Jsm (cf. attachment).
The generic code below relies on libgcc routines, it should work anywhere, doesn't it? (Well, on mingw you won't be able to resolve function names using dladdr(), so you're stuck with the address only, but that's already useful information). Anyway, I don't have time to propose a patch, but the code below works nicely on Mac OS (where gfortran doesn't currently support backtraces). ------------------------------------------ #include <stdlib.h> #include <unistd.h> #include <dlfcn.h> #include <stdio.h> typedef enum { _URC_NO_REASON = 0, _URC_FOREIGN_EXCEPTION_CAUGHT = 1, _URC_FATAL_PHASE2_ERROR = 2, _URC_FATAL_PHASE1_ERROR = 3, _URC_NORMAL_STOP = 4, _URC_END_OF_STACK = 5, _URC_HANDLER_FOUND = 6, _URC_INSTALL_CONTEXT = 7, _URC_CONTINUE_UNWIND = 8 } _Unwind_Reason_Code; struct _Unwind_Context; typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (struct _Unwind_Context *, void *); extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *); #if defined(__ia64__) && defined(__hpux__) typedef unsigned _Unwind_Ptr __attribute__((__mode__(__word__))); #else typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__))); #endif extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *); static _Unwind_Reason_Code trace_function (struct _Unwind_Context *context, void *unused) { void * ip = (void *)(uintptr_t) _Unwind_GetIP (context); Dl_info dlinfo; dladdr (ip, &dlinfo); if (dlinfo.dli_sname != NULL) printf ("%p (%s)\n", ip, dlinfo.dli_sname); else printf ("%p\n", ip); return _URC_NO_REASON; } void show_backtrace (void) { _Unwind_Backtrace (trace_function, NULL); }
(In reply to comment #1) > The generic code below relies on libgcc routines, it should work anywhere, > doesn't it? Well, on x86-64-linux, I needed at least the following modifications: - #include "libgfortran.h" - #include <stdint.h> /* For uintptr_t. */ - On Linux Dl_info does not work by default; as man dladdr states: Glibc adds two functions not described by POSIX, with prototypes #define _GNU_SOURCE /* See feature_test_macros(7) */ #include <dlfcn.h> one could assume that _GNU_SOURCE had do be defined - but that does not work. With #define __USE_GNU it works - trace_function: The unused parameter gives a fatal warning - thus, I used __attribute__((undefined)). Then it compiles - but linking an executable fails with: "undefined reference to `dladdr", unless I link with "-ldl". But then I get a backtrace of the form: 0x2af48a719fa7 0x2af48a7e2019 0x400698 0x400688 0x40067d 0x4006a1 0x4006d7 0x2af48b0dbbfd (__libc_start_main) * * * Regarding the functionality * libgo/configure.ac has the check: GCC_CHECK_UNWIND_GETIPINFO Ditto for libada, libjava and libstdc++-v3. Thus, we might pick some functionality from: * libgo/runtime/go-unwind.c * libjava/exception.cc * libjava/stacktrace.cc
I have a patch: http://gcc.gnu.org/ml/gcc-patches/2011-11/msg00068.html
Author: jb Date: Wed Nov 9 16:04:42 2011 New Revision: 181209 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=181209 Log: PR 46686 Implement backtrace with _Unwind_Backtrace from libgcc. 2011-11-09 Janne Blomqvist <jb@gcc.gnu.org> PR fortran/46686 * configure.ac: Don't check execinfo.h, backtrace, backtrace_symbols_fd. Check execve instead of execvp. Call GCC_CHECK_UNWIND_GETIPINFO. * runtime/backtrace.c: Don't include unused headers, include limits.h and unwind.h. (CAN_FORK): Check execve instead of execvp. (GLIBC_BACKTRACE): Remove. (bt_header): Conform to gdb backtrace format. (struct bt_state): New struct. (trace_function): New function. (show_backtrace): Use _Unwind_Backtrace from libgcc instead of glibc backtrace functions. * Makefile.in: Regenerated. * aclocal.m4: Regenerated. * config.h.in: Regenerated. * configure: Regenerated. Modified: trunk/libgfortran/ChangeLog trunk/libgfortran/Makefile.in trunk/libgfortran/aclocal.m4 trunk/libgfortran/config.h.in trunk/libgfortran/configure trunk/libgfortran/configure.ac trunk/libgfortran/runtime/backtrace.c
Author: jb Date: Wed Nov 9 17:52:11 2011 New Revision: 181217 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=181217 Log: PR 46686 Fix incorrect comment. 2011-11-09 Janne Blomqvist <jb@gcc.gnu.org> PR fortran/46686 * runtime/backtrace.c (show_backtrace): Fix incorrect comment. Modified: trunk/libgfortran/ChangeLog trunk/libgfortran/runtime/backtrace.c
With addr2line, the output looks like: #5 0x40064C in MAIN__ at test.f90:6 without #5 0x40064C TODO: For Windows, one should be able to make use of SymFromAddr + SymGetLineFromAddr64 + IMAGEHLP_LINE64 to obtain the symbol name, the file and the line number. Cf. http://msdn.microsoft.com/en-us/library/windows/desktop/ms681323%28v=vs.85%29.aspx and http://msdn.microsoft.com/en-us/library/windows/desktop/ms680578%28v=vs.85%29.aspx TODO 2: For Darwin exists atos which is similar to addr2line, cf. http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/atos.1.html TODO 3: Update 4.7 release notes.
(In reply to comment #6) > TODO: For Windows, one should be able to make use of SymFromAddr + > SymGetLineFromAddr64 + IMAGEHLP_LINE64 to obtain the symbol name Kai points out that those only work with PDB and not with DWARF. Though, it seems as if addr2line exists also for Windows. Kai thinks that is might/should work if one replaces for MINGW the path separator by ";" in libgfortran/runtime/main.c's find_addr2line. One probably needs to allow '\\' besides '/' under MinGW.
(In reply to comment #7) > (In reply to comment #6) > > TODO: For Windows, one should be able to make use of SymFromAddr + > > SymGetLineFromAddr64 + IMAGEHLP_LINE64 to obtain the symbol name > > Kai points out that those only work with PDB and not with DWARF. > > Though, it seems as if addr2line exists also for Windows. Kai thinks that is > might/should work if one replaces for MINGW the path separator by ";" in > libgfortran/runtime/main.c's find_addr2line. One probably needs to allow '\\' > besides '/' under MinGW. I thought that fork, exec, and pipe, which are necessary for starting and interacting with the addr2line process are not supported on mingw? But, if it works, great!
(In reply to comment #8) > I thought that fork, exec, and pipe, which are necessary for starting and > interacting with the addr2line process are not supported on mingw? I just asked Kai. _exec, _pipe and _dup2 are supported, but fork() is not. However, Kai suggests to use FILE *__cdecl _popen(const char *_Command,const char *_Mode) with _Mode = "rb". One can then read from the stream. See also: http://msdn.microsoft.com/en-us/library/96ayss4b%28v=vs.80%29.aspx
(In reply to comment #9) > (In reply to comment #8) > > I thought that fork, exec, and pipe, which are necessary for starting and > > interacting with the addr2line process are not supported on mingw? > > I just asked Kai. _exec, _pipe and _dup2 are supported, but fork() is not. > However, Kai suggests to use > FILE *__cdecl _popen(const char *_Command,const char *_Mode) > with _Mode = "rb". One can then read from the stream. See also: > http://msdn.microsoft.com/en-us/library/96ayss4b%28v=vs.80%29.aspx At least on POSIX popen() is not async-signal-safe, hence one cannot use it in a signal handler. In any case, unassigning myself, since I have neither the time nor the means to work on the remaining platform-specific parts of this PR.
I think this issue has been fixed now that we use libbacktrace to show backtraces.