diff mbox series

[Ada] Ability to build the GNAT runtime with project files

Message ID 20200530202706.GA134846@adacore.com
State New
Headers show
Series [Ada] Ability to build the GNAT runtime with project files | expand

Commit Message

Arnaud Charlet May 30, 2020, 8:27 p.m. UTC
This change adds project files to provide the ability to rebuild the
runtime with gprbuild after setup-rts is called.

Tested on x86_64-linux-gnu, committed on master
    
    gcc/ada/
    
    	* Makefile.rtl (ADA_INCLUDE_SRCS): Replace Makefile.adalib by
    	libada.gpr and associated project files.
    	(g-debpoo.o): Add missing rule to ensure subprograms are not reordered.
    	(setup-rts): Add generation of libgnat/libgnarl.lst.
    	(LIBGNAT_SRCS): Remove thread.c which is part of libgnarl.
    	* tracebak.c, tb-gcc.c: Merged the two files to simplify dependencies.
    	* libgnarl/libgnarl.gpr, libgnat/libada.gpr,
    	libgnat/libgnat.gpr, libgnat/libgnat_common.gpr: New files.
    	* doc/gnat_ugn/the_gnat_compilation_model.rst: Makefile.adalib
    	replaced by libada.gpr.
    	* libgnat/system-mingw.ads: Remove obsolete comment.
    	* gcc-interface/Makefile.in: Remove dependency on tb-gcc.c.
diff mbox series

Patch

diff --git gcc/ada/Makefile.rtl gcc/ada/Makefile.rtl
index 55ff9b0..0c62df2 100644
--- gcc/ada/Makefile.rtl
+++ gcc/ada/Makefile.rtl
@@ -2621,7 +2621,7 @@  LIBGNAT_OBJS = adadecode.o adaint.o argv.o aux-io.o 			\
 
 LIBGNAT_SRCS = $(patsubst %.o,%.c,$(LIBGNAT_OBJS))			\
   adadecode.h adaint.h env.h gsocket.h raise.h standard.ads.h		\
-  tb-gcc.c runtime.h libgnarl/thread.c $(EXTRA_LIBGNAT_SRCS)
+  runtime.h $(EXTRA_LIBGNAT_SRCS)
 
 # memtrack.o is special as not put into libgnat.
 GNATRTL_OBJS = $(GNATRTL_NONTASKING_OBJS) $(GNATRTL_TASKING_OBJS) \
@@ -2634,7 +2634,8 @@  GNATRTL_OBJS = $(GNATRTL_NONTASKING_OBJS) $(GNATRTL_TASKING_OBJS) \
 ADA_INCLUDE_SRCS =\
  libgnat/ada.ads libgnat/calendar.ads libgnat/directio.ads libgnat/gnat.ads libgnat/interfac.ads libgnat/ioexcept.ads \
  libgnat/machcode.ads libgnat/text_io.ads libgnat/unchconv.ads libgnat/unchdeal.ads \
- libgnat/sequenio.ads libgnat/system.ads Makefile.adalib libgnat/memtrack.adb \
+ libgnat/sequenio.ads libgnat/system.ads libgnat/memtrack.adb \
+ libgna*/*.gpr \
  libgnat/a-[a-o]*.adb libgnat/a-[a-o]*.ads \
  libgnat/a-[p-z]*.adb libgnat/a-[p-z]*.ads \
  libgnat/g-[a-o]*.adb libgnat/g-[a-o]*.ads \
@@ -2680,7 +2681,7 @@  setup-rts: force
 	$(MKDIR) $(RTSDIR)
 	$(CHMOD) u+w $(RTSDIR)
 # Copy target independent sources
-	$(foreach f,$(ADA_INCLUDE_SRCS) $(LIBGNAT_SRCS), \
+	$(foreach f,$(ADA_INCLUDE_SRCS) $(LIBGNAT_SRCS) libgnarl/thread.c, \
 	  $(LN_S) $(GNAT_SRC)/$(f) $(RTSDIR) ;) true
 # Remove files not used
 	$(RM) $(patsubst %,$(RTSDIR)/%,$(ADA_EXCLUDE_FILES))
@@ -2697,6 +2698,25 @@  setup-rts: force
 	$(foreach PAIR,$(LIBGNAT_TARGET_PAIRS), \
 	          $(LN_S) $(GNAT_SRC)/$(word 2,$(subst <, ,$(PAIR))) \
 	                $(RTSDIR)/$(word 1,$(subst <, ,$(PAIR)));)
+# And finally generate libgnat.lst and libgnarl.lst
+	@for f in \
+	  $(foreach F,$(GNATRTL_TASKING_OBJS),$(subst $(objext),.ads,$(F))) \
+	  $(foreach F,$(GNATRTL_TASKING_OBJS),$(subst $(objext),.adb,$(F))); \
+	do \
+	  if [ -f $(RTSDIR)/$$f ]; then echo $$f >> $(RTSDIR)/libgnarl.lst; fi \
+	done
+	@echo thread.c >> $(RTSDIR)/libgnarl.lst
+	@for f in \
+	  $(foreach F,$(GNATRTL_NONTASKING_OBJS),$(subst $(objext),.ads,$(F))) \
+	  $(foreach F,$(GNATRTL_NONTASKING_OBJS),$(subst $(objext),.adb,$(F))); \
+	do \
+	  if [ -f $(RTSDIR)/$$f ]; then echo $$f >> $(RTSDIR)/libgnat.lst; fi \
+	done
+# s-oscons.ads is generated later, so hardcode it here
+	@echo s-oscons.ads >> $(RTSDIR)/libgnat.lst
+	@for f in $(LIBGNAT_SRCS); do \
+	  echo $$f >> $(RTSDIR)/libgnat.lst; \
+	done
 
 # Special flags. It is recommended not to change the compilation flags
 # without a careful analysis of the consequences because (part of) the
@@ -2773,3 +2793,10 @@  a-tags.o  : a-tags.adb a-tags.ads
 s-memory.o  : s-memory.adb s-memory.ads
 	$(ADAC) -c $(ALL_ADAFLAGS) $(NO_SIBLING_ADAFLAGS) $(ADA_INCLUDES) \
 	  $< $(OUTPUT_OPTION)
+
+# Need to keep functions ordered on g-debpoo.o since labels are used to
+# exclude subprograms from traceback computation.
+
+g-debpoo.o: g-debpoo.adb g-debpoo.ads
+	$(ADAC) -c $(ALL_ADAFLAGS) $(NO_REORDER_ADAFLAGS) $(ADA_INCLUDES) \
+	  $< $(OUTPUT_OPTION)
diff --git gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst
index d7388bb..0b587ef 100644
--- gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst
+++ gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst
@@ -2393,10 +2393,9 @@  Rebuilding the GNAT Run-Time Library
 .. index:: Rebuilding the GNAT Run-Time Library
 .. index:: Run-Time Library, rebuilding
 
-It may be useful to recompile the GNAT library in various contexts, the
-most important one being the use of partition-wide configuration pragmas
-such as ``Normalize_Scalars``. A special Makefile called
-:file:`Makefile.adalib` is provided to that effect and can be found in
+It may be useful to recompile the GNAT library in various debugging or
+experimentation contexts. A project file called
+:file:`libada.gpr` is provided to that effect and can be found in
 the directory containing the GNAT library. The location of this
 directory depends on the way the GNAT environment has been installed and can
 be determined by means of the command:
@@ -2405,10 +2404,13 @@  be determined by means of the command:
 
       $ gnatls -v
 
-The last entry in the object search path usually contains the
-gnat library. This Makefile contains its own documentation and in
-particular the set of instructions needed to rebuild a new library and
-to use it.
+The last entry in the source search path usually contains the
+gnat library (the :file:`adainclude` directory). This project file contains its
+own documentation and in particular the set of instructions needed to rebuild a
+new library and to use it.
+
+Note that rebuilding the GNAT Run-Time is only recommended for temporary
+experiments or debugging, and is not supported.
 
 
 .. index:: ! Conditional compilation
diff --git gcc/ada/gcc-interface/Makefile.in gcc/ada/gcc-interface/Makefile.in
index 3342e33..25ebc3d 100644
--- gcc/ada/gcc-interface/Makefile.in
+++ gcc/ada/gcc-interface/Makefile.in
@@ -895,7 +895,7 @@  ADA_RTL_DSO_DIR = $(toolexeclibdir)
 # need to keep the frame pointer in tracebak.o to pop the stack properly on
 # some targets.
 
-tracebak.o  : tracebak.c tb-gcc.c
+tracebak.o  : tracebak.c
 	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ADA_CFLAGS) $(ALL_CPPFLAGS) \
 	      $(INCLUDES) $(NO_OMIT_ADAFLAGS) $< $(OUTPUT_OPTION)
 
diff --git gcc/ada/libgnarl/libgnarl.gpr gcc/ada/libgnarl/libgnarl.gpr
new file mode 100644
index 0000000..3933f6f
--- /dev/null
+++ gcc/ada/libgnarl/libgnarl.gpr
@@ -0,0 +1,28 @@ 
+with "libgnat_common";
+
+library project Libgnarl is
+
+   for Languages use ("Ada", "C");
+   for Source_Dirs use (".");
+   for Source_List_File use "libgnarl.lst";
+   for Object_Dir use "../obj-" & Libgnat_Common.Library_Kind;
+
+   for Library_Name use "gnarl";
+   for Library_Dir use "../adalib";
+   for Library_Kind use Libgnat_Common.Library_Kind;
+
+   package Compiler is
+
+      for Switches ("C") use Libgnat_Common.C_Flags;
+      for Switches ("Ada") use Libgnat_Common.Ada_Flags;
+
+      for Switches ("s-tasdeb.adb") use
+        Libgnat_Common.Ada_Flags &
+        Libgnat_Common.Force_Debug &
+        Libgnat_Common.No_Opt;
+      --  Compile s-tasdeb.o without optimization and with debug info so that
+      --  it is always possible to set conditional breakpoints on tasks.
+
+   end Compiler;
+
+end Libgnarl;
diff --git gcc/ada/libgnat/libada.gpr gcc/ada/libgnat/libada.gpr
new file mode 100644
index 0000000..9453cae
--- /dev/null
+++ gcc/ada/libgnat/libada.gpr
@@ -0,0 +1,77 @@ 
+-- This is a project file used to rebuild the GNAT run-time for debug
+-- or instrumentation purposes.
+--
+-- Here is how to use this project file:
+--
+-- 1. Create a new directory (e.g. "rts-debug"), then copy the adainclude
+--    directory from the reference runtime that you want to rebuild.
+--    You can find the relevant adainclude directory by running the command
+--    gprls [--target=<target>] [--RTS=<runtime>] and using the adainclude
+--    directory listed. For example:
+--     $ cd <reference directory>
+--     $ mkdir rts-debug
+--     $ cd rts-debug
+--     $ cp -a `gprls -v | grep adainclude` .
+--     $ cd adainclude
+--
+--    or under Windows:
+--
+--     $ mkdir adainclude
+--     $ xcopy /s /path/to/adainclude adainclude
+--     $ cd adainclude
+--
+-- 2. If needed (e.g for pragma Normalize_Scalars), create a file called
+--    gnat.adc in the adainclude directory containing the configuration pragmas
+--    you want to use to build the library, e.g.
+--
+--     $ echo "pragma Normalize_Scalars;" > gnat.adc
+--
+--    Note that this step is usually not needed, and most pragmas are not
+--    relevant to the GNAT run time.
+--
+-- 3. Determine the values of the following variables
+--    CFLAGS (back end compilation flags such as -g -O2)
+--    ADAFLAGS (front end compilation flags such as -gnatn)
+--
+-- 4. Run gprbuild on libada.gpr, e.g:
+--    $ gprbuild -p -Plibada -j0 -XCFLAGS="-O2 -g" -XADAFLAGS="-gnatn"
+--
+--    or for a cross target:
+--
+--    $ gprbuild --target=powerpc-elf -p -Plibada -j0 [...]
+--
+--    if you created a gnat.adc file at step 2, add "-XCONFIG_FILE=gnat.adc" to
+--    the gprbuild switches.
+--
+--    The above command will build libgnat.a and libgnarl.a with the given
+--    switches.
+--
+-- 4b. In order to generate shared libraries instead, add
+--    "-XLIBRARY_KIND=dynamic" to the gprbuild switches, and if you want to
+--    build both shared and static libraries, you can run gprbuild twice in
+--    a row, e.g:
+--
+--    $ gprbuild -p -Plibada -j0 -XLIBRARY_KIND=dynamic [...]
+--    $ gprbuild -p -Plibada -j0 -XLIBRARY_KIND=static [...]
+--
+-- 5. Once the above gprbuild command is successful, you can use this new
+--    runtime directory by specifying it either via the --RTS= switch on the
+--    command line or via the attribute Runtime ("Ada") in the main project
+--    file:
+--     $ gprbuild --RTS=.../rts-debug ...
+--    or
+--       for Runtime ("Ada") use ".../rts-debug";
+
+aggregate project Libada is
+   for Project_Files use ("libgnat.gpr", "libgnarl.gpr");
+
+   Config_File := External ("CONFIG_FILE", "");
+
+   package Builder is
+      case Config_File is
+         when ""     => null;
+         when others => for Global_Configuration_Pragmas use Config_File;
+      end case;
+   end Builder;
+
+end Libada;
diff --git gcc/ada/libgnat/libgnat.gpr gcc/ada/libgnat/libgnat.gpr
new file mode 100644
index 0000000..006ff2d
--- /dev/null
+++ gcc/ada/libgnat/libgnat.gpr
@@ -0,0 +1,69 @@ 
+with "libgnat_common";
+
+library project Libgnat is
+
+   for Languages use ("Ada", "C");
+   for Source_Dirs use (".");
+   for Source_List_File use "libgnat.lst";
+   for Object_Dir use "../obj-" & Libgnat_Common.Library_Kind;
+
+   for Library_Name use "gnat";
+   for Library_Dir use "../adalib";
+   for Library_Kind use Libgnat_Common.Library_Kind;
+
+   package Compiler is
+
+      for Switches ("C") use Libgnat_Common.C_Flags;
+      for Switches ("Ada") use Libgnat_Common.Ada_Flags;
+
+      for Switches ("s-traceb.adb") use
+        Libgnat_Common.Ada_Flags & Libgnat_Common.Force_Debug &
+        Libgnat_Common.No_Inline & Libgnat_Common.No_Sibling;
+      --  Force no sibling call optimization on s-traceb.o so the number of
+      --  stack frames to be skipped when computing a call chain is not
+      --  modified by optimization. We don.t want inlining, either.
+
+      for Switches ("a-except.adb") use
+        Libgnat_Common.Ada_Flags & ("-O1") &
+        Libgnat_Common.Force_Debug & Libgnat_Common.No_Inline &
+        Libgnat_Common.No_Reorder;
+      --  Force no function reordering because of the exclusion bounds
+      --  mechanism (see the source file for more detailed information).
+      --  Force debugging information so that it is always possible to set
+      --  conditional breakpoints on exceptions.
+      --  Use -O1 otherwise gdb isn.t able to get a full backtrace on mips
+      --  targets.
+
+      for Switches ("s-excdeb.adb") use
+        Libgnat_Common.Ada_Flags & Libgnat_Common.Force_Debug &
+        Libgnat_Common.No_Opt;
+      --  Compile without optimization and with debug info to let the debugger
+      --  set breakpoints and inspect subprogram parameters on exception
+      --  related events.
+
+      for Switches ("s-assert.adb") use
+        Libgnat_Common.Ada_Flags & Libgnat_Common.Force_Debug;
+      --  Force debugging information on s-assert.o so that it is always
+      --  possible to set breakpoint on assert failures.
+
+      for Switches ("a-tags.adb") use
+        Libgnat_Common.Ada_Flags & Libgnat_Common.Force_Debug;
+      --  Force debugging information on a-tags.o so that the debugger can find
+      --  the description of Ada.Tags.Type_Specific_Data.
+
+      for Switches ("s-memory.adb") use
+        Libgnat_Common.Ada_Flags & Libgnat_Common.No_Sibling;
+      --  Force no sibling call optimization on s-memory.o to avoid turning the
+      --  tail recursion in Alloc into a loop that confuses branch prediction.
+
+      for Switches ("g-debpoo.adb") use
+        Libgnat_Common.Ada_Flags & Libgnat_Common.No_Reorder;
+      --  Need to keep functions ordered on g-debpoo.o since labels are used to
+      --  exclude subprograms from traceback computation.
+
+      for Switches ("traceback.c") use
+        Libgnat_Common.C_Flags & Libgnat_Common.No_Omit;
+
+   end Compiler;
+
+end Libgnat;
diff --git gcc/ada/libgnat/libgnat_common.gpr gcc/ada/libgnat/libgnat_common.gpr
new file mode 100644
index 0000000..6303928
--- /dev/null
+++ gcc/ada/libgnat/libgnat_common.gpr
@@ -0,0 +1,19 @@ 
+abstract project Libgnat_Common is
+
+   Common_Flags := Split (External ("CFLAGS", "-O2 -g"), " ");
+   C_Flags      := Common_Flags &
+                   ("-I../include", "-DIN_RTS=1", "-fexceptions",
+                    "-DSTANDALONE") &
+                   External_As_List ("EXTRALIBFLAGS", " ");
+   Ada_Flags    := Common_Flags & ("-nostdinc", "-I../adainclude")
+                   & Split (External ("ADAFLAGS", "-gnatpg"), " ");
+   Library_Kind := External ("LIBRARY_KIND", "static");
+
+   No_Opt      := ("-O0");
+   Force_Debug := ("-g");
+   No_Inline   := ("-fno-inline");
+   No_Omit     := ("-fno-omit-frame-pointer");
+   No_Sibling  := ("-fno-optimize-sibling-calls");
+   No_Reorder  := ("-fno-toplevel-reorder", "-O0");
+
+end Libgnat_Common;
diff --git gcc/ada/libgnat/system-mingw.ads gcc/ada/libgnat/system-mingw.ads
index 42719e4..3df80e3 100644
--- gcc/ada/libgnat/system-mingw.ads
+++ gcc/ada/libgnat/system-mingw.ads
@@ -185,11 +185,6 @@  private
    --  model, but maps them using compression onto the 7 priority levels
    --  available in NT and on the 16 priority levels available in 2000/XP.
 
-   --  To replace the default values of the Underlying_Priorities mapping,
-   --  copy this source file into your build directory, edit the file to
-   --  reflect your desired behavior, and recompile using Makefile.adalib
-   --  which can be found under the adalib directory of your gnat installation
-
    pragma Linker_Options ("-Wl,--stack=0x2000000");
    --  This is used to change the default stack (32 MB) size for non tasking
    --  programs. We change this value for GNAT on Windows here because the
diff --git gcc/ada/tb-gcc.c gcc/ada/tb-gcc.c
deleted file mode 100644
index 74d0c21..0000000
--- gcc/ada/tb-gcc.c
+++ /dev/null
@@ -1,125 +0,0 @@ 
-/****************************************************************************
- *                                                                          *
- *                         GNAT RUN-TIME COMPONENTS                         *
- *                                                                          *
- *                   T R A C E B A C K - G C C t a b l e s                  *
- *                                                                          *
- *                          C Implementation File                           *
- *                                                                          *
- *          Copyright (C) 2004-2019, Free Software Foundation, Inc.         *
- *                                                                          *
- * GNAT is free software;  you can  redistribute it  and/or modify it under *
- * terms of the  GNU General Public License as published  by the Free Soft- *
- * ware  Foundation;  either version 3,  or (at your option) any later ver- *
- * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
- * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
- * or FITNESS FOR A PARTICULAR PURPOSE.                                     *
- *                                                                          *
- * As a special exception under Section 7 of GPL version 3, you are granted *
- * additional permissions described in the GCC Runtime Library Exception,   *
- * version 3.1, as published by the Free Software Foundation.               *
- *                                                                          *
- * You should have received a copy of the GNU General Public License and    *
- * a copy of the GCC Runtime Library Exception along with this program;     *
- * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    *
- * <http://www.gnu.org/licenses/>.                                          *
- *                                                                          *
- * GNAT was originally developed  by the GNAT team at  New York University. *
- * Extensive contributions were provided by Ada Core Technologies Inc.      *
- *                                                                          *
- ****************************************************************************/
-
-/* This is an implementation of the __gnat_backtrace routine using the
-   underlying GCC unwinding support associated with the exception handling
-   infrastructure.  This will only work for ZCX based applications.  */
-
-#include <unwind.h>
-
-/* The implementation boils down to a call to _Unwind_Backtrace with a
-   tailored callback and carried-on data structure to keep track of the
-   input parameters we got as well as of the basic processing state.  */
-
-/******************
- * trace_callback *
- ******************/
-
-#if !defined (__USING_SJLJ_EXCEPTIONS__)
-
-typedef struct {
-  void ** traceback;
-  int max_len;
-  void * exclude_min;
-  void * exclude_max;
-  int  n_frames_to_skip;
-  int  n_frames_skipped;
-  int  n_entries_filled;
-} uw_data_t;
-
-#if defined (__ia64__) && defined (__hpux__)
-#include <uwx.h>
-#endif
-
-static _Unwind_Reason_Code
-trace_callback (struct _Unwind_Context * uw_context, uw_data_t * uw_data)
-{
-  char * pc;
-
-#if defined (__ia64__) && defined (__hpux__) && defined (USE_LIBUNWIND_EXCEPTIONS)
-  /* Work around problem with _Unwind_GetIP on ia64 HP-UX. */
-  uwx_get_reg ((struct uwx_env *) uw_context, UWX_REG_IP, (uint64_t *) &pc);
-#else
-  pc = (char *) _Unwind_GetIP (uw_context);
-#endif
-
-  if (uw_data->n_frames_skipped < uw_data->n_frames_to_skip)
-    {
-      uw_data->n_frames_skipped ++;
-      return _URC_NO_REASON;
-    }
-
-  if (uw_data->n_entries_filled >= uw_data->max_len)
-    return _URC_NORMAL_STOP;
-
-  if (pc < (char *)uw_data->exclude_min || pc > (char *)uw_data->exclude_max)
-    uw_data->traceback [uw_data->n_entries_filled ++] = pc + PC_ADJUST;
-
-  return _URC_NO_REASON;
-}
-
-#endif
-
-/********************
- * __gnat_backtrace *
- ********************/
-
-int
-__gnat_backtrace (void ** traceback __attribute__((unused)),
-		  int max_len __attribute__((unused)),
-		  void * exclude_min __attribute__((unused)),
-		  void * exclude_max __attribute__((unused)),
-		  int skip_frames __attribute__((unused)))
-{
-#if defined (__USING_SJLJ_EXCEPTIONS__)
-  /* We have no unwind material (tables) at hand with sjlj eh, and no
-     way to retrieve complete and accurate call chain information from
-     the context stack we maintain.  */
-  return 0;
-#else
-  uw_data_t uw_data;
-  /* State carried over during the whole unwinding process.  */
-
-  uw_data.traceback   = traceback;
-  uw_data.max_len     = max_len;
-  uw_data.exclude_min = exclude_min;
-  uw_data.exclude_max = exclude_max;
-
-  uw_data.n_frames_to_skip = skip_frames;
-
-  uw_data.n_frames_skipped = 0;
-  uw_data.n_entries_filled = 0;
-
-  _Unwind_Backtrace ((_Unwind_Trace_Fn)trace_callback, &uw_data);
-
-  return uw_data.n_entries_filled;
-#endif
-}
diff --git gcc/ada/tracebak.c gcc/ada/tracebak.c
index 9e74282..abbe075 100644
--- gcc/ada/tracebak.c
+++ gcc/ada/tracebak.c
@@ -588,7 +588,101 @@  is_return_from(void *symbol_addr, void *ret_addr)
    define it to a reasonable value to avoid a compilation error.  */
 #define _URC_NORMAL_STOP 0
 #endif
-#include "tb-gcc.c"
+
+/* This is an implementation of the __gnat_backtrace routine using the
+   underlying GCC unwinding support associated with the exception handling
+   infrastructure.  This will only work for ZCX based applications.  */
+
+#include <unwind.h>
+
+/* The implementation boils down to a call to _Unwind_Backtrace with a
+   tailored callback and carried-on data structure to keep track of the
+   input parameters we got as well as of the basic processing state.  */
+
+/******************
+ * trace_callback *
+ ******************/
+
+#if !defined (__USING_SJLJ_EXCEPTIONS__)
+
+typedef struct {
+  void ** traceback;
+  int max_len;
+  void * exclude_min;
+  void * exclude_max;
+  int  n_frames_to_skip;
+  int  n_frames_skipped;
+  int  n_entries_filled;
+} uw_data_t;
+
+#if defined (__ia64__) && defined (__hpux__)
+#include <uwx.h>
+#endif
+
+static _Unwind_Reason_Code
+trace_callback (struct _Unwind_Context * uw_context, uw_data_t * uw_data)
+{
+  char * pc;
+
+#if defined (__ia64__) && defined (__hpux__) && defined (USE_LIBUNWIND_EXCEPTIONS)
+  /* Work around problem with _Unwind_GetIP on ia64 HP-UX. */
+  uwx_get_reg ((struct uwx_env *) uw_context, UWX_REG_IP, (uint64_t *) &pc);
+#else
+  pc = (char *) _Unwind_GetIP (uw_context);
+#endif
+
+  if (uw_data->n_frames_skipped < uw_data->n_frames_to_skip)
+    {
+      uw_data->n_frames_skipped ++;
+      return _URC_NO_REASON;
+    }
+
+  if (uw_data->n_entries_filled >= uw_data->max_len)
+    return _URC_NORMAL_STOP;
+
+  if (pc < (char *)uw_data->exclude_min || pc > (char *)uw_data->exclude_max)
+    uw_data->traceback [uw_data->n_entries_filled ++] = pc + PC_ADJUST;
+
+  return _URC_NO_REASON;
+}
+
+#endif
+
+/********************
+ * __gnat_backtrace *
+ ********************/
+
+int
+__gnat_backtrace (void ** traceback __attribute__((unused)),
+		  int max_len __attribute__((unused)),
+		  void * exclude_min __attribute__((unused)),
+		  void * exclude_max __attribute__((unused)),
+		  int skip_frames __attribute__((unused)))
+{
+#if defined (__USING_SJLJ_EXCEPTIONS__)
+  /* We have no unwind material (tables) at hand with sjlj eh, and no
+     way to retrieve complete and accurate call chain information from
+     the context stack we maintain.  */
+  return 0;
+#else
+  uw_data_t uw_data;
+  /* State carried over during the whole unwinding process.  */
+
+  uw_data.traceback   = traceback;
+  uw_data.max_len     = max_len;
+  uw_data.exclude_min = exclude_min;
+  uw_data.exclude_max = exclude_max;
+
+  uw_data.n_frames_to_skip = skip_frames;
+
+  uw_data.n_frames_skipped = 0;
+  uw_data.n_entries_filled = 0;
+
+  _Unwind_Backtrace ((_Unwind_Trace_Fn)trace_callback, &uw_data);
+
+  return uw_data.n_entries_filled;
+#endif
+}
 
 /*------------------------------------------------------------------*
  *-- The generic implementation based on frame layout assumptions --*