Bug 46686 - Improve backtracing (unwinding) on non-glibc targets
Summary: Improve backtracing (unwinding) on non-glibc targets
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.6.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-11-27 16:36 UTC by Tobias Burnus
Modified: 2016-02-01 07:36 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2011-11-01 00:00:00


Attachments
http://pastebin.com/XrxW7Jsm - Unwinding for MinGW(64) (587 bytes, text/plain)
2010-11-27 16:36 UTC, Tobias Burnus
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Burnus 2010-11-27 16:36:27 UTC
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).
Comment 1 Francois-Xavier Coudert 2011-05-06 21:25:24 UTC
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);
}
Comment 2 Tobias Burnus 2011-05-14 21:11:07 UTC
(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
Comment 3 Janne Blomqvist 2011-11-01 18:24:37 UTC
I have a patch: http://gcc.gnu.org/ml/gcc-patches/2011-11/msg00068.html
Comment 4 Janne Blomqvist 2011-11-09 16:04:47 UTC
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
Comment 5 Janne Blomqvist 2011-11-09 17:52:19 UTC
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
Comment 6 Tobias Burnus 2011-11-09 17:57:57 UTC
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.
Comment 7 Tobias Burnus 2011-11-09 19:26:09 UTC
(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.
Comment 8 Janne Blomqvist 2011-11-09 19:38:49 UTC
(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!
Comment 9 Tobias Burnus 2011-11-09 20:13:09 UTC
(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
Comment 10 Janne Blomqvist 2011-11-22 11:24:10 UTC
(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.
Comment 11 Janne Blomqvist 2016-02-01 07:36:23 UTC
I think this issue has been fixed now that we use libbacktrace to show backtraces.