s-dwalin.ads, [...]: New.
authorArnaud Charlet <charlet@gcc.gnu.org>
Fri, 8 Sep 2017 11:00:52 +0000 (13:00 +0200)
committerArnaud Charlet <charlet@gcc.gnu.org>
Fri, 8 Sep 2017 11:00:52 +0000 (13:00 +0200)
2017-09-08  Arnaud Charlet <charlet@adacore.com>

* s-dwalin.ads, s-dwalin.adb, s-trasym-dwarf.adb, s-objrea.ads,
s-objrea.adb, s-tsmona-linux.adb, s-tsmona-mingw.adb: New.
* gcc-interface/Makefile.in: Enable s-trasym-dwarf.adb on x86*linux.

From-SVN: r251887

gcc/ada/gcc-interface/Makefile.in
gcc/ada/s-dwalin.adb [new file with mode: 0644]
gcc/ada/s-dwalin.ads [new file with mode: 0644]
gcc/ada/s-objrea.adb [new file with mode: 0644]
gcc/ada/s-objrea.ads [new file with mode: 0644]
gcc/ada/s-trasym-dwarf.adb [new file with mode: 0644]
gcc/ada/s-tsmona-linux.adb [new file with mode: 0644]
gcc/ada/s-tsmona-mingw.adb [new file with mode: 0644]

index 482259ee3cdfa5dcef1f071772deeb78b26d0835..9ad7783e43b6595dc6a6089d5c9284811fed7a1f 100644 (file)
@@ -429,6 +429,25 @@ X86_64_TARGET_PAIRS = \
   a-numaux.adb<a-numaux-x86.adb \
   s-atocou.adb<s-atocou-builtin.adb
 
+# Implementation of symbolic traceback based on dwarf
+TRASYM_DWARF_UNIX_PAIRS = \
+  s-trasym.adb<s-trasym-dwarf.adb \
+  s-mmosin.ads<s-mmosin-unix.ads \
+  s-mmosin.adb<s-mmosin-unix.adb \
+  s-mmauni.ads<s-mmauni-long.ads
+
+TRASYM_DWARF_MINGW_PAIRS = \
+  s-trasym.adb<s-trasym-dwarf.adb \
+  s-mmosin.ads<s-mmosin-mingw.ads \
+  s-mmosin.adb<s-mmosin-mingw.adb
+
+TRASYM_DWARF_COMMON_OBJS = s-objrea$(objext) s-dwalin$(objext) s-mmap$(objext) \
+  s-mmosin$(objext)
+
+TRASYM_DWARF_UNIX_OBJS = $(TRASYM_DWARF_COMMON_OBJS) s-mmauni$(objext)
+
+TRASYM_DWARF_MINGW_OBJS = $(TRASYM_DWARF_COMMON_OBJS)
+
 # Shared library version
 LIB_VERSION = $(strip $(shell grep ' Library_Version :' $(fsrcpfx)ada/gnatvsn.ads | sed -e 's/.*"\(.*\)".*/\1/'))
 
@@ -1085,7 +1104,9 @@ ifeq ($(strip $(filter-out %86 linux%,$(target_cpu) $(target_os))),)
   s-inmaop.adb<s-inmaop-posix.adb \
   s-intman.adb<s-intman-posix.adb \
   s-tpopsp.adb<s-tpopsp-tls.adb \
+  $(TRASYM_DWARF_UNIX_PAIRS) \
   g-sercom.adb<g-sercom-linux.adb \
+  s-tsmona.adb<s-tsmona-linux.adb \
   a-exetim.adb<a-exetim-posix.adb \
   a-exetim.ads<a-exetim-default.ads \
   s-linux.ads<s-linux.ads \
@@ -1111,6 +1132,7 @@ ifeq ($(strip $(filter-out %86 linux%,$(target_cpu) $(target_os))),)
   EH_MECHANISM=-gcc
   THREADSLIB = -lpthread -lrt
   EXTRA_GNATRTL_NONTASKING_OBJS += g-sse.o g-ssvety.o
+  EXTRA_GNATRTL_NONTASKING_OBJS += $(TRASYM_DWARF_UNIX_OBJS)
   EXTRA_GNATRTL_TASKING_OBJS=s-linux.o a-exetim.o
 
   TOOLS_TARGET_PAIRS = indepsw.adb<indepsw-gnu.adb
@@ -1907,6 +1929,8 @@ ifeq ($(strip $(filter-out %x86_64 linux%,$(target_cpu) $(target_os))),)
   s-tpopsp.adb<s-tpopsp-tls.adb \
   s-taspri.ads<s-taspri-posix.ads \
   g-sercom.adb<g-sercom-linux.adb \
+  $(TRASYM_DWARF_UNIX_PAIRS) \
+  s-tsmona.adb<s-tsmona-linux.adb \
   $(ATOMICS_TARGET_PAIRS) \
   $(X86_64_TARGET_PAIRS) \
   system.ads<system-linux-x86.ads
@@ -1914,6 +1938,7 @@ ifeq ($(strip $(filter-out %x86_64 linux%,$(target_cpu) $(target_os))),)
   TOOLS_TARGET_PAIRS = indepsw.adb<indepsw-gnu.adb
 
   EXTRA_GNATRTL_NONTASKING_OBJS += g-sse.o g-ssvety.o
+  EXTRA_GNATRTL_NONTASKING_OBJS += $(TRASYM_DWARF_UNIX_OBJS)
   EXTRA_GNATRTL_TASKING_OBJS=s-linux.o a-exetim.o
 
   EH_MECHANISM=-gcc
diff --git a/gcc/ada/s-dwalin.adb b/gcc/ada/s-dwalin.adb
new file mode 100644 (file)
index 0000000..1791b2d
--- /dev/null
@@ -0,0 +1,1627 @@
+------------------------------------------------------------------------------
+--                                                                          --
+--                         GNAT COMPILER COMPONENTS                         --
+--                                                                          --
+--                   S Y S T E M . D W A R F _ L I N E S                    --
+--                                                                          --
+--                                 B o d y                                  --
+--                                                                          --
+--          Copyright (C) 2009-2017, 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.      --
+--                                                                          --
+------------------------------------------------------------------------------
+
+pragma Polling (Off);
+--  We must turn polling off for this unit, because otherwise we can get
+--  elaboration circularities when polling is turned on
+
+with Ada.Characters.Handling;
+with Ada.Exceptions.Traceback; use Ada.Exceptions.Traceback;
+with Ada.Unchecked_Deallocation;
+with Ada.Containers.Generic_Array_Sort;
+
+with Interfaces; use Interfaces;
+
+with System;                   use System;
+with System.Storage_Elements;  use System.Storage_Elements;
+with System.Address_Image;
+with System.IO;                use System.IO;
+with System.Object_Reader;     use System.Object_Reader;
+with System.Traceback_Entries; use System.Traceback_Entries;
+with System.Mmap;              use System.Mmap;
+with System.Bounded_Strings;   use System.Bounded_Strings;
+
+package body System.Dwarf_Lines is
+
+   SSU : constant := System.Storage_Unit;
+
+   function String_Length (Str : Str_Access) return Natural;
+   --  Return the length of the C string Str
+
+   ---------------------------------
+   -- DWARF Parser Implementation --
+   ---------------------------------
+
+   procedure Read_Initial_Length
+     (S    : in out Mapped_Stream;
+      Len  :    out Offset;
+      Is64 :    out Boolean);
+   --  Read initial length as specified by Dwarf-4 7.2.2
+
+   procedure Read_Section_Offset
+     (S    : in out Mapped_Stream;
+      Len  :    out Offset;
+      Is64 :        Boolean);
+   --  Read a section offset, as specified by Dwarf-4 7.4
+
+   procedure Read_Aranges_Entry
+     (C     : in out Dwarf_Context;
+      Start :    out Integer_Address;
+      Len   :    out Storage_Count);
+   --  Read a single .debug_aranges pair
+
+   procedure Read_Aranges_Header
+     (C           : in out Dwarf_Context;
+      Info_Offset :    out Offset;
+      Success     :    out Boolean);
+   --  Read .debug_aranges header
+
+   procedure Aranges_Lookup
+     (C           : in out Dwarf_Context;
+      Addr        :        Address;
+      Info_Offset :    out Offset;
+      Success     :    out Boolean);
+   --  Search for Addr in .debug_aranges and return offset Info_Offset in
+   --  .debug_info.
+
+   procedure Skip_Form
+     (S      : in out Mapped_Stream;
+      Form   :        uint32;
+      Is64   :        Boolean;
+      Ptr_Sz :        uint8);
+   --  Advance offset in S for Form.
+
+   procedure Seek_Abbrev
+     (C             : in out Dwarf_Context;
+      Abbrev_Offset :        Offset;
+      Abbrev_Num    :        uint32);
+   --  Seek to abbrev Abbrev_Num (starting from Abbrev_Offset)
+
+   procedure Debug_Info_Lookup
+     (C           : in out Dwarf_Context;
+      Info_Offset :        Offset;
+      Line_Offset :    out Offset;
+      Success     :    out Boolean);
+   --  Search for stmt_list tag in Info_Offset and set Line_Offset to the
+   --  offset in .debug_lines. Only look at the first DIE, which should be
+   --  a compilation unit.
+
+   procedure Initialize_Pass (C : in out Dwarf_Context);
+   --  Seek to the first byte of the first prologue and prepare to make a pass
+   --  over the line number entries.
+
+   procedure Initialize_State_Machine (C : in out Dwarf_Context);
+   --  Set all state machine registers to their specified initial values
+
+   procedure Parse_Prologue (C : in out Dwarf_Context);
+   --  Decode a DWARF statement program prologue
+
+   procedure Read_And_Execute_Isn
+     (C    : in out Dwarf_Context;
+      Done :    out Boolean);
+   --  Read an execute a statement program instruction
+
+   function To_File_Name
+     (C    : in out Dwarf_Context;
+      Code :        uint32) return String;
+   --  Extract a file name from the prologue
+
+   type Callback is access procedure (C : in out Dwarf_Context);
+   procedure For_Each_Row (C : in out Dwarf_Context; F : Callback);
+   --  Traverse each .debug_line entry with a callback
+
+   procedure Dump_Row (C : in out Dwarf_Context);
+   --  Dump a single row
+
+   function "<" (Left, Right : Search_Entry) return Boolean;
+   --  For sorting Search_Entry
+
+   procedure Sort_Search_Array is new Ada.Containers.Generic_Array_Sort
+     (Index_Type   => Natural,
+      Element_Type => Search_Entry,
+      Array_Type   => Search_Array);
+
+   procedure Symbolic_Address
+     (C           : in out Dwarf_Context;
+      Addr        :        Address;
+      Dir_Name    :    out Str_Access;
+      File_Name   :    out Str_Access;
+      Subprg_Name :    out String_Ptr_Len;
+      Line_Num    :    out Natural);
+   --  Symbolize one address
+
+   -----------------------
+   --  DWARF constants  --
+   -----------------------
+
+   --  6.2.5.2 Standard Opcodes
+
+   DW_LNS_copy               : constant := 1;
+   DW_LNS_advance_pc         : constant := 2;
+   DW_LNS_advance_line       : constant := 3;
+   DW_LNS_set_file           : constant := 4;
+   DW_LNS_set_column         : constant := 5;
+   DW_LNS_negate_stmt        : constant := 6;
+   DW_LNS_set_basic_block    : constant := 7;
+   DW_LNS_const_add_pc       : constant := 8;
+   DW_LNS_fixed_advance_pc   : constant := 9;
+   DW_LNS_set_prologue_end   : constant := 10;
+   DW_LNS_set_epilogue_begin : constant := 11;
+   DW_LNS_set_isa            : constant := 12;
+
+   --  6.2.5.3 Extended Opcodes
+
+   DW_LNE_end_sequence : constant := 1;
+   DW_LNE_set_address  : constant := 2;
+   DW_LNE_define_file  : constant := 3;
+
+   --  From the DWARF version 4 public review draft
+
+   DW_LNE_set_discriminator : constant := 4;
+
+   --  Attribute encodings
+
+   DW_TAG_Compile_Unit : constant := 16#11#;
+
+   DW_AT_Stmt_List : constant := 16#10#;
+
+   DW_FORM_addr         : constant := 16#01#;
+   DW_FORM_block2       : constant := 16#03#;
+   DW_FORM_block4       : constant := 16#04#;
+   DW_FORM_data2        : constant := 16#05#;
+   DW_FORM_data4        : constant := 16#06#;
+   DW_FORM_data8        : constant := 16#07#;
+   DW_FORM_string       : constant := 16#08#;
+   DW_FORM_block        : constant := 16#09#;
+   DW_FORM_block1       : constant := 16#0a#;
+   DW_FORM_data1        : constant := 16#0b#;
+   DW_FORM_flag         : constant := 16#0c#;
+   DW_FORM_sdata        : constant := 16#0d#;
+   DW_FORM_strp         : constant := 16#0e#;
+   DW_FORM_udata        : constant := 16#0f#;
+   DW_FORM_ref_addr     : constant := 16#10#;
+   DW_FORM_ref1         : constant := 16#11#;
+   DW_FORM_ref2         : constant := 16#12#;
+   DW_FORM_ref4         : constant := 16#13#;
+   DW_FORM_ref8         : constant := 16#14#;
+   DW_FORM_ref_udata    : constant := 16#15#;
+   DW_FORM_indirect     : constant := 16#16#;
+   DW_FORM_sec_offset   : constant := 16#17#;
+   DW_FORM_exprloc      : constant := 16#18#;
+   DW_FORM_flag_present : constant := 16#19#;
+   DW_FORM_ref_sig8     : constant := 16#20#;
+
+   ---------
+   -- "<" --
+   ---------
+
+   function "<" (Left, Right : Search_Entry) return Boolean is
+   begin
+      return Left.First < Right.First;
+   end "<";
+
+   -----------
+   -- Close --
+   -----------
+
+   procedure Close (C : in out Dwarf_Context) is
+      procedure Unchecked_Deallocation is new Ada.Unchecked_Deallocation
+        (Object_File,
+         Object_File_Access);
+      procedure Unchecked_Deallocation is new Ada.Unchecked_Deallocation
+        (Search_Array,
+         Search_Array_Access);
+   begin
+      if C.Has_Debug then
+         Close (C.Lines);
+         Close (C.Abbrev);
+         Close (C.Info);
+         Close (C.Aranges);
+      end if;
+
+      Close (C.Obj.all);
+      Unchecked_Deallocation (C.Obj);
+
+      Unchecked_Deallocation (C.Cache);
+   end Close;
+
+   ----------
+   -- Dump --
+   ----------
+
+   procedure Dump (C : in out Dwarf_Context) is
+   begin
+      For_Each_Row (C, Dump_Row'Access);
+   end Dump;
+
+   --------------
+   -- Dump_Row --
+   --------------
+
+   procedure Dump_Row (C : in out Dwarf_Context) is
+      PC  : constant Integer_Address := Integer_Address (C.Registers.Address);
+      Off : Offset;
+   begin
+      Tell (C.Lines, Off);
+
+      Put (System.Address_Image (To_Address (PC)));
+      Put (" ");
+      Put (To_File_Name (C, C.Registers.File));
+      Put (":");
+
+      declare
+         Image : constant String := uint32'Image (C.Registers.Line);
+      begin
+         Put_Line (Image (2 .. Image'Last));
+      end;
+
+      Seek (C.Lines, Off);
+   end Dump_Row;
+
+   procedure Dump_Cache (C : Dwarf_Context) is
+      Cache : constant Search_Array_Access := C.Cache;
+      S     : Object_Symbol;
+      Name  : String_Ptr_Len;
+   begin
+      if Cache = null then
+         Put_Line ("No cache");
+         return;
+      end if;
+      for I in Cache'Range loop
+         Put (System.Address_Image (C.Low + Storage_Count (Cache (I).First)));
+         Put (" - ");
+         Put
+           (System.Address_Image
+              (C.Low + Storage_Count (Cache (I).First + Cache (I).Size)));
+         Put (" l@");
+         Put
+           (System.Address_Image
+              (To_Address (Integer_Address (Cache (I).Line))));
+         Put (": ");
+         S    := Read_Symbol (C.Obj.all, Offset (Cache (I).Sym));
+         Name := Object_Reader.Name (C.Obj.all, S);
+         Put (String (Name.Ptr (1 .. Name.Len)));
+         New_Line;
+      end loop;
+   end Dump_Cache;
+
+   ------------------
+   -- For_Each_Row --
+   ------------------
+
+   procedure For_Each_Row (C : in out Dwarf_Context; F : Callback) is
+      Done : Boolean;
+
+   begin
+      Initialize_Pass (C);
+
+      loop
+         Read_And_Execute_Isn (C, Done);
+
+         if C.Registers.Is_Row then
+            F.all (C);
+         end if;
+
+         exit when Done;
+      end loop;
+   end For_Each_Row;
+
+   ---------------------
+   -- Initialize_Pass --
+   ---------------------
+
+   procedure Initialize_Pass (C : in out Dwarf_Context) is
+   begin
+      Seek (C.Lines, 0);
+      C.Next_Prologue := 0;
+
+      Initialize_State_Machine (C);
+   end Initialize_Pass;
+
+   ------------------------------
+   -- Initialize_State_Machine --
+   ------------------------------
+
+   procedure Initialize_State_Machine (C : in out Dwarf_Context) is
+   begin
+      C.Registers :=
+        (Address        => 0,
+         File           => 1,
+         Line           => 1,
+         Column         => 0,
+         Is_Stmt        => C.Prologue.Default_Is_Stmt = 0,
+         Basic_Block    => False,
+         End_Sequence   => False,
+         Prologue_End   => False,
+         Epilogue_Begin => False,
+         ISA            => 0,
+         Is_Row         => False);
+   end Initialize_State_Machine;
+
+   ---------------
+   -- Is_Inside --
+   ---------------
+
+   function Is_Inside (C : Dwarf_Context; Addr : Address) return Boolean is
+   begin
+      return Addr >= C.Low and Addr <= C.High;
+   end Is_Inside;
+
+   ---------
+   -- Low --
+   ---------
+
+   function Low (C : Dwarf_Context) return Address is
+   begin
+      return C.Low;
+   end Low;
+
+   ----------
+   -- Open --
+   ----------
+
+   procedure Open
+     (File_Name :     String;
+      C         : out Dwarf_Context;
+      Success   : out Boolean)
+   is
+      Line_Sec, Info_Sec, Abbrev_Sec, Aranges_Sec : Object_Section;
+      Hi, Lo                                      : uint64;
+   begin
+      --  Not a success by default
+
+      Success := False;
+
+      --  Open file
+
+      C.Obj := Open (File_Name, C.In_Exception);
+
+      if C.Obj = null then
+         return;
+      end if;
+
+      Success := True;
+
+      --  Get memory bounds
+
+      Get_Memory_Bounds (C.Obj.all, Lo, Hi);
+      C.Low  := Address (Lo);
+      C.High := Address (Hi);
+
+      --  Create a stream for debug sections
+
+      if Format (C.Obj.all) = XCOFF32 then
+         Line_Sec    := Get_Section (C.Obj.all, ".dwline");
+         Abbrev_Sec  := Get_Section (C.Obj.all, ".dwabrev");
+         Info_Sec    := Get_Section (C.Obj.all, ".dwinfo");
+         Aranges_Sec := Get_Section (C.Obj.all, ".dwarnge");
+      else
+         Line_Sec    := Get_Section (C.Obj.all, ".debug_line");
+         Abbrev_Sec  := Get_Section (C.Obj.all, ".debug_abbrev");
+         Info_Sec    := Get_Section (C.Obj.all, ".debug_info");
+         Aranges_Sec := Get_Section (C.Obj.all, ".debug_aranges");
+      end if;
+
+      if Line_Sec = Null_Section
+        or else Abbrev_Sec = Null_Section
+        or else Info_Sec = Null_Section
+        or else Aranges_Sec = Null_Section
+      then
+         C.Has_Debug := False;
+         return;
+      end if;
+
+      C.Lines   := Create_Stream (C.Obj.all, Line_Sec);
+      C.Abbrev  := Create_Stream (C.Obj.all, Abbrev_Sec);
+      C.Info    := Create_Stream (C.Obj.all, Info_Sec);
+      C.Aranges := Create_Stream (C.Obj.all, Aranges_Sec);
+
+      --  All operations are successful, context is valid
+
+      C.Has_Debug := True;
+   end Open;
+
+   --------------------
+   -- Parse_Prologue --
+   --------------------
+
+   procedure Parse_Prologue (C : in out Dwarf_Context) is
+      Char : uint8;
+      Prev : uint8;
+      --  The most recently read character and the one preceding it
+
+      Dummy : uint32;
+      --  Destination for reads we don't care about
+
+      Buf : Buffer;
+      Off : Offset;
+
+      First_Byte_Of_Prologue : Offset;
+      Last_Byte_Of_Prologue  : Offset;
+
+      Max_Op_Per_Insn : uint8;
+      pragma Unreferenced (Max_Op_Per_Insn);
+
+      Prologue : Line_Info_Prologue renames C.Prologue;
+
+   begin
+      Tell (C.Lines, First_Byte_Of_Prologue);
+      Prologue.Unit_Length := Read (C.Lines);
+      Tell (C.Lines, Off);
+      C.Next_Prologue := Off + Offset (Prologue.Unit_Length);
+
+      Prologue.Version         := Read (C.Lines);
+      Prologue.Prologue_Length := Read (C.Lines);
+      Tell (C.Lines, Last_Byte_Of_Prologue);
+      Last_Byte_Of_Prologue :=
+        Last_Byte_Of_Prologue + Offset (Prologue.Prologue_Length) - 1;
+
+      Prologue.Min_Isn_Length := Read (C.Lines);
+
+      if Prologue.Version >= 4 then
+         Max_Op_Per_Insn := Read (C.Lines);
+      end if;
+
+      Prologue.Default_Is_Stmt := Read (C.Lines);
+      Prologue.Line_Base       := Read (C.Lines);
+      Prologue.Line_Range      := Read (C.Lines);
+      Prologue.Opcode_Base     := Read (C.Lines);
+
+      --  Opcode_Lengths is an array of Opcode_Base bytes specifying the number
+      --  of LEB128 operands for each of the standard opcodes.
+
+      for J in 1 .. uint32 (Prologue.Opcode_Base - 1) loop
+         Prologue.Opcode_Lengths (J) := Read (C.Lines);
+      end loop;
+
+      --  The include directories table follows. This is a list of null
+      --  terminated strings terminated by a double null. We only store
+      --  its offset for later decoding.
+
+      Tell (C.Lines, Prologue.Includes_Offset);
+      Char := Read (C.Lines);
+
+      if Char /= 0 then
+         loop
+            Prev := Char;
+            Char := Read (C.Lines);
+            exit when Char = 0 and Prev = 0;
+         end loop;
+      end if;
+
+      --  The file_names table is next. Each record is a null terminated string
+      --  for the file name, an unsigned LEB128 directory index, an unsigned
+      --  LEB128 modification time, and an LEB128 file length. The table is
+      --  terminated by a null byte.
+
+      Tell (C.Lines, Prologue.File_Names_Offset);
+
+      loop
+         --  Read the filename
+
+         Read_C_String (C.Lines, Buf);
+         exit when Buf (0) = 0;
+         Dummy := Read_LEB128 (C.Lines); --  Skip the directory index.
+         Dummy := Read_LEB128 (C.Lines); --  Skip the modification time.
+         Dummy := Read_LEB128 (C.Lines); --  Skip the file length.
+      end loop;
+
+      --  Check we're where we think we are. This sanity check ensures we think
+      --  the prologue ends where the prologue says it does. It we aren't then
+      --  we've probably gotten out of sync somewhere.
+
+      Tell (C.Lines, Off);
+
+      if Prologue.Unit_Length /= 0
+        and then Off /= Last_Byte_Of_Prologue + 1
+      then
+         raise Dwarf_Error with "Parse error reading DWARF information";
+      end if;
+   end Parse_Prologue;
+
+   --------------------------
+   -- Read_And_Execute_Isn --
+   --------------------------
+
+   procedure Read_And_Execute_Isn
+     (C    : in out Dwarf_Context;
+      Done :    out Boolean)
+   is
+      Opcode          : uint8;
+      Extended_Opcode : uint8;
+      uint32_Operand  : uint32;
+      int32_Operand   : int32;
+      uint16_Operand  : uint16;
+      Off             : Offset;
+
+      Extended_Length : uint32;
+      pragma Unreferenced (Extended_Length);
+
+      Obj : Object_File renames C.Obj.all;
+      Registers : Line_Info_Registers renames C.Registers;
+      Prologue : Line_Info_Prologue renames C.Prologue;
+
+   begin
+      Done             := False;
+      Registers.Is_Row := False;
+
+      if Registers.End_Sequence then
+         Initialize_State_Machine (C);
+      end if;
+
+      --  Read the next prologue
+
+      Tell (C.Lines, Off);
+      while Off = C.Next_Prologue loop
+         Initialize_State_Machine (C);
+         Parse_Prologue (C);
+         Tell (C.Lines, Off);
+         exit when Off + 4 >= Length (C.Lines);
+      end loop;
+
+      --  Test whether we're done
+
+      Tell (C.Lines, Off);
+
+      --  We are finished when we either reach the end of the section, or we
+      --  have reached zero padding at the end of the section.
+
+      if Prologue.Unit_Length = 0 or else Off + 4 >= Length (C.Lines) then
+         Done := True;
+         return;
+      end if;
+
+      --  Read and interpret an instruction
+
+      Opcode := Read (C.Lines);
+
+      --  Extended opcodes
+
+      if Opcode = 0 then
+         Extended_Length := Read_LEB128 (C.Lines);
+         Extended_Opcode := Read (C.Lines);
+
+         case Extended_Opcode is
+            when DW_LNE_end_sequence =>
+
+               --  Mark the end of a sequence of source locations
+
+               Registers.End_Sequence := True;
+               Registers.Is_Row       := True;
+
+            when DW_LNE_set_address =>
+
+               --  Set the program counter to a word
+
+               Registers.Address := Read_Address (Obj, C.Lines);
+
+            when DW_LNE_define_file =>
+
+               --  Not implemented
+
+               raise Dwarf_Error with "DWARF operator not implemented";
+
+            when DW_LNE_set_discriminator =>
+
+               --  Ignored
+
+               int32_Operand := Read_LEB128 (C.Lines);
+
+            when others =>
+
+               --  Fail on an unrecognized opcode
+
+               raise Dwarf_Error with "DWARF operator not implemented";
+         end case;
+
+      --  Standard opcodes
+
+      elsif Opcode < Prologue.Opcode_Base then
+         case Opcode is
+
+            --  Append a row to the line info matrix
+
+            when DW_LNS_copy =>
+               Registers.Basic_Block := False;
+               Registers.Is_Row      := True;
+
+            --  Add an unsigned word to the program counter
+
+            when DW_LNS_advance_pc =>
+               uint32_Operand    := Read_LEB128 (C.Lines);
+               Registers.Address :=
+                 Registers.Address +
+                 uint64 (uint32_Operand * uint32 (Prologue.Min_Isn_Length));
+
+            --  Add a signed word to the current source line
+
+            when DW_LNS_advance_line =>
+               int32_Operand  := Read_LEB128 (C.Lines);
+               Registers.Line :=
+                 uint32 (int32 (Registers.Line) + int32_Operand);
+
+            --  Set the current source file
+
+            when DW_LNS_set_file =>
+               uint32_Operand := Read_LEB128 (C.Lines);
+               Registers.File := uint32_Operand;
+
+            --  Set the current source column
+
+            when DW_LNS_set_column =>
+               uint32_Operand   := Read_LEB128 (C.Lines);
+               Registers.Column := uint32_Operand;
+
+            --  Toggle the "is statement" flag. GCC doesn't seem to set this???
+
+            when DW_LNS_negate_stmt =>
+               Registers.Is_Stmt := not Registers.Is_Stmt;
+
+            --  Mark the beginning of a basic block
+
+            when DW_LNS_set_basic_block =>
+               Registers.Basic_Block := True;
+
+            --  Advance the program counter as by the special opcode 255
+
+            when DW_LNS_const_add_pc =>
+               Registers.Address :=
+                 Registers.Address +
+                 uint64
+                   (((255 - Prologue.Opcode_Base) / Prologue.Line_Range) *
+                    Prologue.Min_Isn_Length);
+
+            --  Advance the program counter by a constant
+
+            when DW_LNS_fixed_advance_pc =>
+               uint16_Operand    := Read (C.Lines);
+               Registers.Address :=
+                 Registers.Address + uint64 (uint16_Operand);
+
+            --  The following are not implemented and ignored
+
+            when DW_LNS_set_prologue_end =>
+               null;
+
+            when DW_LNS_set_epilogue_begin =>
+               null;
+
+            when DW_LNS_set_isa =>
+               null;
+
+            --  Anything else is an error
+
+            when others =>
+               raise Dwarf_Error with "DWARF operator not implemented";
+         end case;
+
+      --  Decode a special opcode. This is a line and address increment encoded
+      --  in a single byte 'special opcode' as described in 6.2.5.1.
+
+      else
+         declare
+            Address_Increment : int32;
+            Line_Increment    : int32;
+
+         begin
+            Opcode := Opcode - Prologue.Opcode_Base;
+
+            --  The adjusted opcode is a uint8 encoding an address increment
+            --  and a signed line increment. The upperbound is allowed to be
+            --  greater than int8'last so we decode using int32 directly to
+            --  prevent overflows.
+
+            Address_Increment :=
+              int32 (Opcode / Prologue.Line_Range) *
+              int32 (Prologue.Min_Isn_Length);
+            Line_Increment :=
+              int32 (Prologue.Line_Base) +
+              int32 (Opcode mod Prologue.Line_Range);
+
+            Registers.Address :=
+              Registers.Address + uint64 (Address_Increment);
+            Registers.Line := uint32 (int32 (Registers.Line) + Line_Increment);
+            Registers.Basic_Block    := False;
+            Registers.Prologue_End   := False;
+            Registers.Epilogue_Begin := False;
+            Registers.Is_Row         := True;
+         end;
+      end if;
+
+   exception
+      when Dwarf_Error =>
+
+         --  In case of errors during parse, just stop reading
+
+         Registers.Is_Row := False;
+         Done             := True;
+   end Read_And_Execute_Isn;
+
+   ----------------------
+   -- Set_Load_Address --
+   ----------------------
+
+   procedure Set_Load_Address (C : in out Dwarf_Context; Addr : Address) is
+   begin
+      if Addr = Null_Address then
+         return;
+      else
+         C.Load_Slide :=
+           To_Integer (Addr) - Integer_Address (Get_Load_Address (C.Obj.all));
+
+         C.Low  := To_Address (To_Integer (C.Low) + C.Load_Slide);
+         C.High := To_Address (To_Integer (C.High) + C.Load_Slide);
+      end if;
+   end Set_Load_Address;
+
+   ------------------
+   -- To_File_Name --
+   ------------------
+
+   function To_File_Name
+     (C    : in out Dwarf_Context;
+      Code :        uint32) return String
+   is
+      Buf : Buffer;
+      J   : uint32;
+
+      Dir_Idx : uint32;
+      pragma Unreferenced (Dir_Idx);
+
+      Mod_Time : uint32;
+      pragma Unreferenced (Mod_Time);
+
+      Length : uint32;
+      pragma Unreferenced (Length);
+
+   begin
+      Seek (C.Lines, C.Prologue.File_Names_Offset);
+
+      --  Find the entry
+
+      J := 0;
+      loop
+         J := J + 1;
+         Read_C_String (C.Lines, Buf);
+
+         if Buf (Buf'First) = 0 then
+            return "???";
+         end if;
+
+         Dir_Idx  := Read_LEB128 (C.Lines);
+         Mod_Time := Read_LEB128 (C.Lines);
+         Length   := Read_LEB128 (C.Lines);
+         exit when J = Code;
+      end loop;
+
+      return To_String (Buf);
+   end To_File_Name;
+
+   -------------------------
+   -- Read_Initial_Length --
+   -------------------------
+
+   procedure Read_Initial_Length
+     (S    : in out Mapped_Stream;
+      Len  :    out Offset;
+      Is64 :    out Boolean)
+   is
+      Len32 : uint32;
+      Len64 : uint64;
+   begin
+      Len32 := Read (S);
+      if Len32 < 16#ffff_fff0# then
+         Is64 := False;
+         Len  := Offset (Len32);
+      elsif Len32 < 16#ffff_ffff# then
+         --  Invalid length
+         raise Constraint_Error;
+      else
+         Is64  := True;
+         Len64 := Read (S);
+         Len   := Offset (Len64);
+      end if;
+   end Read_Initial_Length;
+
+   -------------------------
+   -- Read_Section_Offset --
+   -------------------------
+
+   procedure Read_Section_Offset
+     (S    : in out Mapped_Stream;
+      Len  :    out Offset;
+      Is64 :        Boolean)
+   is
+   begin
+      if Is64 then
+         Len := Offset (uint64'(Read (S)));
+      else
+         Len := Offset (uint32'(Read (S)));
+      end if;
+   end Read_Section_Offset;
+
+   --------------------
+   -- Aranges_Lookup --
+   --------------------
+
+   procedure Aranges_Lookup
+     (C           : in out Dwarf_Context;
+      Addr        :        Address;
+      Info_Offset :    out Offset;
+      Success     :    out Boolean)
+   is
+   begin
+      Seek (C.Aranges, 0);
+
+      while Tell (C.Aranges) < Length (C.Aranges) loop
+         Read_Aranges_Header (C, Info_Offset, Success);
+         exit when not Success;
+
+         loop
+            declare
+               Start : Integer_Address;
+               Len   : Storage_Count;
+            begin
+               Read_Aranges_Entry (C, Start, Len);
+               exit when Start = 0 and Len = 0;
+               if Addr >= To_Address (Start)
+                 and then Addr < To_Address (Start) + Len
+               then
+                  Success := True;
+                  return;
+               end if;
+            end;
+         end loop;
+      end loop;
+      Success := False;
+   end Aranges_Lookup;
+
+   ---------------
+   -- Skip_Form --
+   ---------------
+
+   procedure Skip_Form
+     (S      : in out Mapped_Stream;
+      Form   :        uint32;
+      Is64   :        Boolean;
+      Ptr_Sz :        uint8)
+   is
+      Skip : Offset;
+   begin
+      case Form is
+         when DW_FORM_addr =>
+            Skip := Offset (Ptr_Sz);
+         when DW_FORM_block2 =>
+            Skip := Offset (uint16'(Read (S)));
+         when DW_FORM_block4 =>
+            Skip := Offset (uint32'(Read (S)));
+         when DW_FORM_data2 | DW_FORM_ref2 =>
+            Skip := 2;
+         when DW_FORM_data4 | DW_FORM_ref4 =>
+            Skip := 4;
+         when DW_FORM_data8 | DW_FORM_ref8 | DW_FORM_ref_sig8 =>
+            Skip := 8;
+         when DW_FORM_string =>
+            while uint8'(Read (S)) /= 0 loop
+               null;
+            end loop;
+            return;
+         when DW_FORM_block | DW_FORM_exprloc =>
+            Skip := Offset (uint32'(Read_LEB128 (S)));
+         when DW_FORM_block1 | DW_FORM_ref1 =>
+            Skip := Offset (uint8'(Read (S)));
+         when DW_FORM_data1 | DW_FORM_flag =>
+            Skip := 1;
+         when DW_FORM_sdata =>
+            declare
+               Val : constant int32 := Read_LEB128 (S);
+               pragma Unreferenced (Val);
+            begin
+               return;
+            end;
+         when DW_FORM_strp | DW_FORM_ref_addr | DW_FORM_sec_offset =>
+            Skip := (if Is64 then 8 else 4);
+         when DW_FORM_udata | DW_FORM_ref_udata =>
+            declare
+               Val : constant uint32 := Read_LEB128 (S);
+               pragma Unreferenced (Val);
+            begin
+               return;
+            end;
+         when DW_FORM_flag_present =>
+            return;
+         when DW_FORM_indirect =>
+            raise Constraint_Error;
+         when others =>
+            raise Constraint_Error;
+      end case;
+      Seek (S, Tell (S) + Skip);
+   end Skip_Form;
+
+   -----------------
+   -- Seek_Abbrev --
+   -----------------
+
+   procedure Seek_Abbrev
+     (C             : in out Dwarf_Context;
+      Abbrev_Offset :        Offset;
+      Abbrev_Num    :        uint32)
+   is
+      Num       : uint32;
+      Abbrev    : uint32;
+      Tag       : uint32;
+      Has_Child : uint8;
+      pragma Unreferenced (Abbrev, Tag, Has_Child);
+   begin
+      Seek (C.Abbrev, Abbrev_Offset);
+
+      Num := 1;
+
+      loop
+         exit when Num = Abbrev_Num;
+
+         Abbrev    := Read_LEB128 (C.Abbrev);
+         Tag       := Read_LEB128 (C.Abbrev);
+         Has_Child := Read (C.Abbrev);
+
+         loop
+            declare
+               Name : constant uint32 := Read_LEB128 (C.Abbrev);
+               Form : constant uint32 := Read_LEB128 (C.Abbrev);
+            begin
+               exit when Name = 0 and Form = 0;
+            end;
+         end loop;
+
+         Num := Num + 1;
+      end loop;
+   end Seek_Abbrev;
+
+   -----------------------
+   -- Debug_Info_Lookup --
+   -----------------------
+
+   procedure Debug_Info_Lookup
+     (C           : in out Dwarf_Context;
+      Info_Offset :        Offset;
+      Line_Offset :    out Offset;
+      Success     :    out Boolean)
+   is
+      Unit_Length   : Offset;
+      Is64          : Boolean;
+      Version       : uint16;
+      Abbrev_Offset : Offset;
+      Addr_Sz       : uint8;
+      Abbrev        : uint32;
+      Has_Child     : uint8;
+      pragma Unreferenced (Has_Child);
+   begin
+      Success := False;
+
+      Seek (C.Info, Info_Offset);
+
+      Read_Initial_Length (C.Info, Unit_Length, Is64);
+
+      Version := Read (C.Info);
+      if Version not in 2 .. 4 then
+         return;
+      end if;
+
+      Read_Section_Offset (C.Info, Abbrev_Offset, Is64);
+
+      Addr_Sz := Read (C.Info);
+      if Addr_Sz /= (Address'Size / SSU) then
+         return;
+      end if;
+
+      --  Read DIEs
+
+      loop
+         Abbrev := Read_LEB128 (C.Info);
+         exit when Abbrev /= 0;
+      end loop;
+
+      --  Read abbrev table
+
+      Seek_Abbrev (C, Abbrev_Offset, Abbrev);
+
+      --  First ULEB128 is the abbrev code
+
+      if Read_LEB128 (C.Abbrev) /= Abbrev then
+         --  Ill formed abbrev table
+         return;
+      end if;
+
+      --  Then the tag
+
+      if Read_LEB128 (C.Abbrev) /= uint32'(DW_TAG_Compile_Unit) then
+         --  Expect compile unit
+         return;
+      end if;
+
+      --  Then the has child flag
+
+      Has_Child := Read (C.Abbrev);
+
+      loop
+         declare
+            Name : constant uint32 := Read_LEB128 (C.Abbrev);
+            Form : constant uint32 := Read_LEB128 (C.Abbrev);
+         begin
+            exit when Name = 0 and Form = 0;
+            if Name = DW_AT_Stmt_List then
+               case Form is
+                  when DW_FORM_sec_offset =>
+                     Read_Section_Offset (C.Info, Line_Offset, Is64);
+                  when DW_FORM_data4 =>
+                     Line_Offset := Offset (uint32'(Read (C.Info)));
+                  when DW_FORM_data8 =>
+                     Line_Offset := Offset (uint64'(Read (C.Info)));
+                  when others =>
+                     --  Unhandled form
+                     return;
+               end case;
+
+               Success := True;
+               return;
+            else
+               Skip_Form (C.Info, Form, Is64, Addr_Sz);
+            end if;
+         end;
+      end loop;
+
+      return;
+   end Debug_Info_Lookup;
+
+   -------------------------
+   -- Read_Aranges_Header --
+   -------------------------
+
+   procedure Read_Aranges_Header
+     (C           : in out Dwarf_Context;
+      Info_Offset :    out Offset;
+      Success     :    out Boolean)
+   is
+      Unit_Length : Offset;
+      Is64        : Boolean;
+      Version     : uint16;
+      Sz          : uint8;
+   begin
+      Success := False;
+
+      Read_Initial_Length (C.Aranges, Unit_Length, Is64);
+
+      Version := Read (C.Aranges);
+      if Version /= 2 then
+         return;
+      end if;
+
+      Read_Section_Offset (C.Aranges, Info_Offset, Is64);
+
+      --  Read address_size (ubyte)
+
+      Sz := Read (C.Aranges);
+      if Sz /= (Address'Size / SSU) then
+         return;
+      end if;
+
+      --  Read segment_size (ubyte)
+
+      Sz := Read (C.Aranges);
+      if Sz /= 0 then
+         return;
+      end if;
+
+      --  Handle alignment on twice the address size
+      declare
+         Cur_Off : constant Offset := Tell (C.Aranges);
+         Align   : constant Offset := 2 * Address'Size / SSU;
+         Space   : constant Offset := Cur_Off mod Align;
+      begin
+         if Space /= 0 then
+            Seek (C.Aranges, Cur_Off + Align - Space);
+         end if;
+      end;
+
+      Success := True;
+   end Read_Aranges_Header;
+
+   ------------------------
+   -- Read_Aranges_Entry --
+   ------------------------
+
+   procedure Read_Aranges_Entry
+     (C     : in out Dwarf_Context;
+      Start :    out Integer_Address;
+      Len   :    out Storage_Count)
+   is
+   begin
+      --  Read table
+      if Address'Size = 32 then
+         declare
+            S, L : uint32;
+         begin
+            S     := Read (C.Aranges);
+            L     := Read (C.Aranges);
+            Start := Integer_Address (S);
+            Len   := Storage_Count (L);
+         end;
+      elsif Address'Size = 64 then
+         declare
+            S, L : uint64;
+         begin
+            S     := Read (C.Aranges);
+            L     := Read (C.Aranges);
+            Start := Integer_Address (S);
+            Len   := Storage_Count (L);
+         end;
+      else
+         raise Constraint_Error;
+      end if;
+   end Read_Aranges_Entry;
+
+   ------------------
+   -- Enable_Cache --
+   ------------------
+
+   procedure Enable_Cache (C : in out Dwarf_Context) is
+      Cache : Search_Array_Access;
+   begin
+      --  Phase 1: count number of symbols. Phase 2: fill the cache.
+      declare
+         S               : Object_Symbol;
+         Sz              : uint32;
+         Addr, Prev_Addr : uint32;
+         Nbr_Symbols     : Natural;
+      begin
+         for Phase in 1 .. 2 loop
+            Nbr_Symbols := 0;
+            S           := First_Symbol (C.Obj.all);
+            Prev_Addr   := uint32'Last;
+            while S /= Null_Symbol loop
+               --  Discard symbols whose length is 0
+               Sz := uint32 (Size (S));
+
+               --  Try to filter symbols at the same address. This is a best
+               --  effort as they might not be consecutive.
+               Addr := uint32 (Value (S) - uint64 (C.Low));
+               if Sz > 0 and then Addr /= Prev_Addr then
+                  Nbr_Symbols := Nbr_Symbols + 1;
+                  Prev_Addr   := Addr;
+
+                  if Phase = 2 then
+                     C.Cache (Nbr_Symbols) :=
+                       (First => Addr,
+                        Size  => Sz,
+                        Sym   => uint32 (Off (S)),
+                        Line  => 0);
+                  end if;
+               end if;
+
+               S := Next_Symbol (C.Obj.all, S);
+            end loop;
+
+            if Phase = 1 then
+               --  Allocate the cache
+               Cache   := new Search_Array (1 .. Nbr_Symbols);
+               C.Cache := Cache;
+            end if;
+         end loop;
+         pragma Assert (Nbr_Symbols = C.Cache'Last);
+      end;
+
+      --  Sort the cache.
+      Sort_Search_Array (C.Cache.all);
+
+      --  Set line offsets
+      if not C.Has_Debug then
+         return;
+      end if;
+      declare
+         Info_Offset : Offset;
+         Line_Offset : Offset;
+         Success     : Boolean;
+         Ar_Start    : Integer_Address;
+         Ar_Len      : Storage_Count;
+         Start, Len  : uint32;
+         First, Last : Natural;
+         Mid         : Natural;
+      begin
+         Seek (C.Aranges, 0);
+
+         while Tell (C.Aranges) < Length (C.Aranges) loop
+            Read_Aranges_Header (C, Info_Offset, Success);
+            exit when not Success;
+
+            Debug_Info_Lookup (C, Info_Offset, Line_Offset, Success);
+            exit when not Success;
+
+            --  Read table
+            loop
+               Read_Aranges_Entry (C, Ar_Start, Ar_Len);
+               exit when Ar_Start = 0 and Ar_Len = 0;
+
+               Len   := uint32 (Ar_Len);
+               Start := uint32 (Ar_Start - To_Integer (C.Low));
+
+               --  Search START in the array
+               First := Cache'First;
+               Last  := Cache'Last;
+               Mid := First;  --  In case of array with one element
+               while First < Last loop
+                  Mid := First + (Last - First) / 2;
+                  if Start < Cache (Mid).First then
+                     Last := Mid - 1;
+                  elsif Start >= Cache (Mid).First + Cache (Mid).Size then
+                     First := Mid + 1;
+                  else
+                     exit;
+                  end if;
+               end loop;
+
+               --  Fill info.
+
+               --  There can be overlapping symbols
+               while Mid > Cache'First
+                 and then Cache (Mid - 1).First <= Start
+                 and then Cache (Mid - 1).First + Cache (Mid - 1).Size > Start
+               loop
+                  Mid := Mid - 1;
+               end loop;
+               while Mid <= Cache'Last loop
+                  if Start < Cache (Mid).First + Cache (Mid).Size
+                    and then Start + Len > Cache (Mid).First
+                  then
+                     --  MID is within the bounds
+                     Cache (Mid).Line := uint32 (Line_Offset);
+                  elsif Start + Len <= Cache (Mid).First then
+                     --  Over
+                     exit;
+                  end if;
+                  Mid := Mid + 1;
+               end loop;
+            end loop;
+         end loop;
+      end;
+   end Enable_Cache;
+
+   ----------------------
+   -- Symbolic_Address --
+   ----------------------
+
+   procedure Symbolic_Address
+     (C           : in out Dwarf_Context;
+      Addr        :        Address;
+      Dir_Name    :    out Str_Access;
+      File_Name   :    out Str_Access;
+      Subprg_Name :    out String_Ptr_Len;
+      Line_Num    :    out Natural)
+   is
+      procedure Set_Result (Match : Line_Info_Registers);
+      --  Set results using match
+
+      procedure Set_Result (Match : Line_Info_Registers) is
+         Dir_Idx : uint32;
+         J       : uint32;
+
+         Mod_Time : uint32;
+         pragma Unreferenced (Mod_Time);
+
+         Length : uint32;
+         pragma Unreferenced (Length);
+
+      begin
+         Seek (C.Lines, C.Prologue.File_Names_Offset);
+
+         --  Find the entry
+
+         J := 0;
+         loop
+            J         := J + 1;
+            File_Name := Read_C_String (C.Lines);
+
+            if File_Name (File_Name'First) = ASCII.NUL then
+               --  End of file list, so incorrect entry
+               return;
+            end if;
+
+            Dir_Idx  := Read_LEB128 (C.Lines);
+            Mod_Time := Read_LEB128 (C.Lines);
+            Length   := Read_LEB128 (C.Lines);
+            exit when J = Match.File;
+         end loop;
+
+         if Dir_Idx = 0 then
+            --  No directory
+            Dir_Name := null;
+
+         else
+            Seek (C.Lines, C.Prologue.Includes_Offset);
+
+            J := 0;
+            loop
+               J        := J + 1;
+               Dir_Name := Read_C_String (C.Lines);
+
+               if Dir_Name (Dir_Name'First) = ASCII.NUL then
+                  --  End of directory list, so ill-formed table
+                  return;
+               end if;
+
+               exit when J = Dir_Idx;
+
+            end loop;
+         end if;
+
+         Line_Num := Natural (Match.Line);
+      end Set_Result;
+
+      Addr_Int     : constant Integer_Address := To_Integer (Addr);
+      Previous_Row : Line_Info_Registers;
+      Info_Offset  : Offset;
+      Line_Offset  : Offset;
+      Success      : Boolean;
+      Done         : Boolean;
+      S            : Object_Symbol;
+   begin
+      --  Initialize result
+      Dir_Name    := null;
+      File_Name   := null;
+      Subprg_Name := (null, 0);
+      Line_Num    := 0;
+
+      if C.Cache /= null then
+         --  Look in the cache
+         declare
+            Addr_Off         : constant uint32 := uint32 (Addr - C.Low);
+            First, Last, Mid : Natural;
+         begin
+            First := C.Cache'First;
+            Last  := C.Cache'Last;
+            while First <= Last loop
+               Mid := First + (Last - First) / 2;
+               if Addr_Off < C.Cache (Mid).First then
+                  Last := Mid - 1;
+               elsif Addr_Off >= C.Cache (Mid).First + C.Cache (Mid).Size then
+                  First := Mid + 1;
+               else
+                  exit;
+               end if;
+            end loop;
+            if Addr_Off >= C.Cache (Mid).First
+              and then Addr_Off < C.Cache (Mid).First + C.Cache (Mid).Size
+            then
+               Line_Offset := Offset (C.Cache (Mid).Line);
+               S := Read_Symbol (C.Obj.all, Offset (C.Cache (Mid).Sym));
+               Subprg_Name := Object_Reader.Name (C.Obj.all, S);
+            else
+               --  Not found
+               return;
+            end if;
+         end;
+      else
+         --  Search symbol
+         S := First_Symbol (C.Obj.all);
+         while S /= Null_Symbol loop
+            if Spans (S, uint64 (Addr_Int)) then
+               Subprg_Name := Object_Reader.Name (C.Obj.all, S);
+               exit;
+            end if;
+
+            S := Next_Symbol (C.Obj.all, S);
+         end loop;
+
+         --  Search address in aranges table
+
+         Aranges_Lookup (C, Addr, Info_Offset, Success);
+         if not Success then
+            return;
+         end if;
+
+         --  Search stmt_list in info table
+
+         Debug_Info_Lookup (C, Info_Offset, Line_Offset, Success);
+         if not Success then
+            return;
+         end if;
+      end if;
+
+      Seek (C.Lines, Line_Offset);
+      C.Next_Prologue := 0;
+      Initialize_State_Machine (C);
+      Parse_Prologue (C);
+
+      --  Advance to the first entry
+
+      loop
+         Read_And_Execute_Isn (C, Done);
+
+         if C.Registers.Is_Row then
+            Previous_Row := C.Registers;
+            exit;
+         end if;
+
+         exit when Done;
+      end loop;
+
+      --  Read the rest of the entries
+
+      while Tell (C.Lines) < C.Next_Prologue loop
+         Read_And_Execute_Isn (C, Done);
+
+         if C.Registers.Is_Row then
+            if not Previous_Row.End_Sequence
+              and then Addr_Int >= Integer_Address (Previous_Row.Address)
+              and then Addr_Int < Integer_Address (C.Registers.Address)
+            then
+               Set_Result (Previous_Row);
+               return;
+
+            elsif Addr_Int = Integer_Address (C.Registers.Address) then
+               Set_Result (C.Registers);
+               return;
+            end if;
+
+            Previous_Row := C.Registers;
+         end if;
+
+         exit when Done;
+      end loop;
+   end Symbolic_Address;
+
+   -------------------
+   -- String_Length --
+   -------------------
+
+   function String_Length (Str : Str_Access) return Natural is
+   begin
+      for I in Str'Range loop
+         if Str (I) = ASCII.NUL then
+            return I - Str'First;
+         end if;
+      end loop;
+      return Str'Last;
+   end String_Length;
+
+   ------------------------
+   -- Symbolic_Traceback --
+   ------------------------
+
+   procedure Symbolic_Traceback
+     (Cin          :        Dwarf_Context;
+      Traceback    :        AET.Tracebacks_Array;
+      Suppress_Hex :        Boolean;
+      Symbol_Found : in out Boolean;
+      Res          : in out System.Bounded_Strings.Bounded_String)
+   is
+      use Ada.Characters.Handling;
+      C    : Dwarf_Context := Cin;
+      Addr : Address;
+
+      Dir_Name    : Str_Access;
+      File_Name   : Str_Access;
+      Subprg_Name : String_Ptr_Len;
+      Line_Num    : Natural;
+      Off         : Natural;
+   begin
+      if not C.Has_Debug then
+         Symbol_Found := False;
+         return;
+      else
+         Symbol_Found := True;
+      end if;
+
+      for J in Traceback'Range loop
+         --  If the buffer is full, no need to do any useless work
+         exit when Is_Full (Res);
+
+         Addr := PC_For (Traceback (J));
+         Symbolic_Address
+           (C,
+            To_Address (To_Integer (Addr) + C.Load_Slide),
+            Dir_Name,
+            File_Name,
+            Subprg_Name,
+            Line_Num);
+
+         if File_Name /= null then
+            declare
+               Last   : constant Natural := String_Length (File_Name);
+               Is_Ada : constant Boolean :=
+                 Last > 3
+                 and then
+                   To_Upper (String (File_Name (Last - 3 .. Last - 1))) =
+                   ".AD";
+               --  True if this is an Ada file. This doesn't take into account
+               --  nonstandard file-naming conventions, but that's OK; this is
+               --  purely cosmetic. It covers at least .ads, .adb, and .ada.
+
+               Line_Image : constant String := Natural'Image (Line_Num);
+            begin
+               if Subprg_Name.Len /= 0 then
+                  --  For Ada code, Symbol_Image is in all lower case; we don't
+                  --  have the case from the original source code. But the best
+                  --  guess is Mixed_Case, so convert to that.
+
+                  if Is_Ada then
+                     declare
+                        Symbol_Image : String :=
+                          Object_Reader.Decoded_Ada_Name
+                            (C.Obj.all,
+                             Subprg_Name);
+                     begin
+                        for K in Symbol_Image'Range loop
+                           if K = Symbol_Image'First
+                             or else not
+                             (Is_Letter (Symbol_Image (K - 1))
+                              or else Is_Digit (Symbol_Image (K - 1)))
+                           then
+                              Symbol_Image (K) := To_Upper (Symbol_Image (K));
+                           end if;
+                        end loop;
+                        Append (Res, Symbol_Image);
+                     end;
+                  else
+                     Off := Strip_Leading_Char (C.Obj.all, Subprg_Name);
+
+                     Append
+                       (Res,
+                        String (Subprg_Name.Ptr (Off .. Subprg_Name.Len)));
+                  end if;
+                  Append (Res, ' ');
+               end if;
+
+               Append (Res, "at ");
+               Append (Res, String (File_Name (1 .. Last)));
+               Append (Res, ':');
+               Append (Res, Line_Image (2 .. Line_Image'Last));
+            end;
+         else
+            if Suppress_Hex then
+               Append (Res, "...");
+            else
+               Append_Address (Res, Addr);
+            end if;
+
+            if Subprg_Name.Len > 0 then
+               Off := Strip_Leading_Char (C.Obj.all, Subprg_Name);
+
+               Append (Res, ' ');
+               Append (Res, String (Subprg_Name.Ptr (Off .. Subprg_Name.Len)));
+            end if;
+
+            Append (Res, " at ???");
+         end if;
+
+         Append (Res, ASCII.LF);
+      end loop;
+   end Symbolic_Traceback;
+end System.Dwarf_Lines;
diff --git a/gcc/ada/s-dwalin.ads b/gcc/ada/s-dwalin.ads
new file mode 100644 (file)
index 0000000..3608fef
--- /dev/null
@@ -0,0 +1,191 @@
+------------------------------------------------------------------------------
+--                                                                          --
+--                         GNAT COMPILER COMPONENTS                         --
+--                                                                          --
+--                   S Y S T E M . D W A R F _ L I N E S                    --
+--                                                                          --
+--                                 S p e c                                  --
+--                                                                          --
+--           Copyright (C) 2009-2017, 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 package provides routines to read DWARF line number information from
+--  a generic object file with as little overhead as possible. This allows
+--  conversions from PC addresses to human readable source locations.
+--
+--  Objects must be built with debugging information, however only the
+--  .debug_line section of the object file is referenced. In cases where object
+--  size is a consideration it's possible to strip all other .debug sections,
+--  which will decrease the size of the object significantly.
+
+pragma Polling (Off);
+--  We must turn polling off for this unit, because otherwise we can get
+--  elaboration circularities when polling is turned on
+
+with Ada.Exceptions.Traceback;
+
+with System.Object_Reader;
+with System.Storage_Elements;
+with System.Bounded_Strings;
+
+package System.Dwarf_Lines is
+
+   package AET renames Ada.Exceptions.Traceback;
+   package SOR renames System.Object_Reader;
+
+   type Dwarf_Context (In_Exception : Boolean := False) is private;
+   --  Type encapsulation the state of the Dwarf reader. When In_Exception
+   --  is True we are parsing as part of a exception handler decorator, we do
+   --  not want an exception to be raised, the parsing is done safely skipping
+   --  DWARF file that cannot be read or with stripped debug section for
+   --  example.
+
+   procedure Open
+     (File_Name :     String;
+      C         : out Dwarf_Context;
+      Success   : out Boolean);
+   procedure Close (C : in out Dwarf_Context);
+   --  Open and close files
+
+   procedure Set_Load_Address (C : in out Dwarf_Context; Addr : Address);
+   --  Set the load address of a file. This is used to rebase PIE (Position
+   --  Independant Executable) binaries.
+
+   function Is_Inside (C : Dwarf_Context; Addr : Address) return Boolean;
+   pragma Inline (Is_Inside);
+   --  Return true iff Addr is within the module
+
+   function Low (C : Dwarf_Context) return Address;
+   pragma Inline (Low);
+   --  Return the lowest address of C
+
+   procedure Dump (C : in out Dwarf_Context);
+   --  Dump each row found in the object's .debug_lines section to standard out
+
+   procedure Dump_Cache (C : Dwarf_Context);
+   --  Dump the cache (if present)
+
+   procedure Enable_Cache (C : in out Dwarf_Context);
+   --  Read symbols information to speed up Symbolic_Traceback.
+
+   procedure Symbolic_Traceback
+     (Cin          :        Dwarf_Context;
+      Traceback    :        AET.Tracebacks_Array;
+      Suppress_Hex :        Boolean;
+      Symbol_Found : in out Boolean;
+      Res          : in out System.Bounded_Strings.Bounded_String);
+   --  Generate a string for a traceback suitable for displaying to the user.
+   --  If one or more symbols are found, Symbol_Found is set to True. This
+   --  allows the caller to fall back to hexadecimal addresses.
+
+   Dwarf_Error : exception;
+   --  Raised if a problem is encountered parsing DWARF information. Can be a
+   --  result of a logic error or malformed DWARF information.
+
+private
+   --  The following section numbers reference
+
+   --    "DWARF Debugging Information Format, Version 3"
+
+   --  published by the Standards Group, http://freestandards.org.
+
+   --  6.2.2 State Machine Registers
+
+   type Line_Info_Registers is record
+      Address        : SOR.uint64;
+      File           : SOR.uint32;
+      Line           : SOR.uint32;
+      Column         : SOR.uint32;
+      Is_Stmt        : Boolean;
+      Basic_Block    : Boolean;
+      End_Sequence   : Boolean;
+      Prologue_End   : Boolean;
+      Epilogue_Begin : Boolean;
+      ISA            : SOR.uint32;
+      Is_Row         : Boolean;
+   end record;
+
+   --  6.2.4 The Line Number Program Prologue
+
+   MAX_OPCODE_LENGTHS : constant := 256;
+
+   type Opcodes_Lengths_Array is
+     array (SOR.uint32 range 1 .. MAX_OPCODE_LENGTHS) of SOR.uint8;
+
+   type Line_Info_Prologue is record
+      Unit_Length       : SOR.uint32;
+      Version           : SOR.uint16;
+      Prologue_Length   : SOR.uint32;
+      Min_Isn_Length    : SOR.uint8;
+      Default_Is_Stmt   : SOR.uint8;
+      Line_Base         : SOR.int8;
+      Line_Range        : SOR.uint8;
+      Opcode_Base       : SOR.uint8;
+      Opcode_Lengths    : Opcodes_Lengths_Array;
+      Includes_Offset   : SOR.Offset;
+      File_Names_Offset : SOR.Offset;
+   end record;
+
+   type Search_Entry is record
+      First : SOR.uint32;
+      Size  : SOR.uint32;
+      --  Function bounds as offset to the base address.
+
+      Sym : SOR.uint32;
+      --  Symbol offset to get the name.
+
+      Line : SOR.uint32;
+      --  Dwarf line offset.
+   end record;
+
+   type Search_Array is array (Natural range <>) of Search_Entry;
+
+   type Search_Array_Access is access Search_Array;
+
+   type Dwarf_Context (In_Exception : Boolean := False) is record
+      Load_Slide : System.Storage_Elements.Integer_Address := 0;
+      Low, High  : Address;
+      --  Bounds of the module
+
+      Obj : SOR.Object_File_Access;
+      --  The object file containing dwarf sections
+
+      Has_Debug : Boolean;
+      --  True if all debug sections are available
+
+      Cache : Search_Array_Access;
+      --  Quick access to symbol and debug info (when present).
+
+      Lines   : SOR.Mapped_Stream;
+      Aranges : SOR.Mapped_Stream;
+      Info    : SOR.Mapped_Stream;
+      Abbrev  : SOR.Mapped_Stream;
+      --  Dwarf line, aranges, info and abbrev sections
+
+      Prologue      : Line_Info_Prologue;
+      Registers     : Line_Info_Registers;
+      Next_Prologue : SOR.Offset;
+      --  State for lines
+   end record;
+
+end System.Dwarf_Lines;
diff --git a/gcc/ada/s-objrea.adb b/gcc/ada/s-objrea.adb
new file mode 100644 (file)
index 0000000..451abcd
--- /dev/null
@@ -0,0 +1,2246 @@
+------------------------------------------------------------------------------
+--                                                                          --
+--                         GNAT COMPILER COMPONENTS                         --
+--                                                                          --
+--                 S Y S T E M . O B J E C T _ R E A D E R                  --
+--                                                                          --
+--                                 B o d y                                  --
+--                                                                          --
+--         Copyright (C) 2009-2017, 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.      --
+--                                                                          --
+------------------------------------------------------------------------------
+
+with Ada.Unchecked_Conversion;
+
+with Interfaces.C;
+
+with System.CRTL;
+
+package body System.Object_Reader is
+   use Interfaces;
+   use Interfaces.C;
+   use System.Mmap;
+
+   SSU : constant := System.Storage_Unit;
+
+   function To_int32 is new Ada.Unchecked_Conversion (uint32, int32);
+
+   function Trim_Trailing_Nuls (Str : String) return String;
+   --  Return a copy of a string with any trailing NUL characters truncated
+
+   procedure Check_Read_Offset (S : in out Mapped_Stream; Size : uint32);
+   --  Check that the SIZE bytes at the current offset are still in the stream
+
+   -------------------------------------
+   -- ELF object file format handling --
+   -------------------------------------
+
+   generic
+      type uword is mod <>;
+
+   package ELF_Ops is
+
+      --  ELF version codes
+
+      ELFCLASS32 : constant := 1;  --  32 bit ELF
+      ELFCLASS64 : constant := 2;  --  64 bit ELF
+
+      --  ELF machine codes
+
+      EM_NONE        : constant :=  0; --  No machine
+      EM_SPARC       : constant :=  2; --  SUN SPARC
+      EM_386         : constant :=  3; --  Intel 80386
+      EM_MIPS        : constant :=  8; --  MIPS RS3000 Big-Endian
+      EM_MIPS_RS3_LE : constant := 10; --  MIPS RS3000 Little-Endian
+      EM_SPARC32PLUS : constant := 18; --  Sun SPARC 32+
+      EM_PPC         : constant := 20; --  PowerPC
+      EM_PPC64       : constant := 21; --  PowerPC 64-bit
+      EM_ARM         : constant := 40; --  ARM
+      EM_SPARCV9     : constant := 43; --  SPARC v9 64-bit
+      EM_IA_64       : constant := 50; --  Intel Merced
+      EM_X86_64      : constant := 62; --  AMD x86-64 architecture
+
+      EN_NIDENT  : constant := 16;
+
+      type E_Ident_Type is array (0 .. EN_NIDENT - 1) of uint8;
+
+      type Header is record
+         E_Ident     : E_Ident_Type; -- Magic number and other info
+         E_Type      : uint16;       -- Object file type
+         E_Machine   : uint16;       -- Architecture
+         E_Version   : uint32;       -- Object file version
+         E_Entry     : uword;        -- Entry point virtual address
+         E_Phoff     : uword;        -- Program header table file offset
+         E_Shoff     : uword;        -- Section header table file offset
+         E_Flags     : uint32;       -- Processor-specific flags
+         E_Ehsize    : uint16;       -- ELF header size in bytes
+         E_Phentsize : uint16;       -- Program header table entry size
+         E_Phnum     : uint16;       -- Program header table entry count
+         E_Shentsize : uint16;       -- Section header table entry size
+         E_Shnum     : uint16;       -- Section header table entry count
+         E_Shstrndx  : uint16;       -- Section header string table index
+      end record;
+
+      type Section_Header is record
+         Sh_Name      : uint32; -- Section name string table index
+         Sh_Type      : uint32; -- Section type
+         Sh_Flags     : uword;  -- Section flags
+         Sh_Addr      : uword;  -- Section virtual addr at execution
+         Sh_Offset    : uword;  -- Section file offset
+         Sh_Size      : uword;  -- Section size in bytes
+         Sh_Link      : uint32; -- Link to another section
+         Sh_Info      : uint32; -- Additional section information
+         Sh_Addralign : uword;  -- Section alignment
+         Sh_Entsize   : uword;  -- Entry size if section holds table
+      end record;
+
+      SHF_ALLOC : constant := 2;
+
+      type Symtab_Entry32 is record
+         St_Name  : uint32;  --  Name (string table index)
+         St_Value : uint32;  --  Value
+         St_Size  : uint32;  --  Size in bytes
+         St_Info  : uint8;   --  Type and binding attributes
+         St_Other : uint8;   --  Undefined
+         St_Shndx : uint16;  --  Defining section
+      end record;
+
+      type Symtab_Entry64 is record
+         St_Name  : uint32;  --  Name (string table index)
+         St_Info  : uint8;   --  Type and binding attributes
+         St_Other : uint8;   --  Undefined
+         St_Shndx : uint16;  --  Defining section
+         St_Value : uint64;  --  Value
+         St_Size  : uint64;  --  Size in bytes
+      end record;
+
+      function Read_Header (F : in out Mapped_Stream) return Header;
+      --  Read a header from an ELF format object
+
+      function First_Symbol
+        (Obj : in out ELF_Object_File) return Object_Symbol;
+      --  Return the first element in the symbol table, or Null_Symbol if the
+      --  symbol table is empty.
+
+      function Read_Symbol
+        (Obj : in out ELF_Object_File;
+         Off : Offset) return Object_Symbol;
+      --  Read a symbol at offset Off
+
+      function Name
+        (Obj : in out ELF_Object_File;
+         Sym : Object_Symbol) return String_Ptr_Len;
+      --  Return the name of the symbol
+
+      function Name
+        (Obj : in out ELF_Object_File;
+         Sec : Object_Section) return String;
+      --  Return the name of a section
+
+      function Get_Section
+        (Obj   : in out ELF_Object_File;
+         Shnum : uint32) return Object_Section;
+      --  Fetch a section by index from zero
+
+      function Initialize
+        (F            : Mapped_File;
+         Hdr          : Header;
+         In_Exception : Boolean) return ELF_Object_File;
+      --  Initialize an object file
+
+   end ELF_Ops;
+
+   -----------------------------------
+   -- PECOFF object format handling --
+   -----------------------------------
+
+   package PECOFF_Ops is
+
+      --  Constants and data layout are taken from the document "Microsoft
+      --  Portable Executable and Common Object File Format Specification"
+      --  Revision 8.1.
+
+      Signature_Loc_Offset : constant := 16#3C#;
+      --  Offset of pointer to the file signature
+
+      Size_Of_Standard_Header_Fields : constant := 16#18#;
+      --  Length in bytes of the standard header record
+
+      Function_Symbol_Type : constant := 16#20#;
+      --  Type field value indicating a symbol refers to a function
+
+      Not_Function_Symbol_Type : constant := 16#00#;
+      --  Type field value indicating a symbol does not refer to a function
+
+      type Magic_Array is array (0 .. 3) of uint8;
+      --  Array of magic numbers from the header
+
+      --  Magic numbers for PECOFF variants
+
+      VARIANT_PE32      : constant := 16#010B#;
+      VARIANT_PE32_PLUS : constant := 16#020B#;
+
+      --  PECOFF machine codes
+
+      IMAGE_FILE_MACHINE_I386  : constant := 16#014C#;
+      IMAGE_FILE_MACHINE_IA64  : constant := 16#0200#;
+      IMAGE_FILE_MACHINE_AMD64 : constant := 16#8664#;
+
+      --  PECOFF Data layout
+
+      type Header is record
+         Magics               : Magic_Array;
+         Machine              : uint16;
+         NumberOfSections     : uint16;
+         TimeDateStamp        : uint32;
+         PointerToSymbolTable : uint32;
+         NumberOfSymbols      : uint32;
+         SizeOfOptionalHeader : uint16;
+         Characteristics      : uint16;
+         Variant              : uint16;
+      end record;
+
+      pragma Pack (Header);
+
+      type Optional_Header_PE32 is record
+         Magic                       : uint16;
+         MajorLinkerVersion          : uint8;
+         MinorLinkerVersion          : uint8;
+         SizeOfCode                  : uint32;
+         SizeOfInitializedData       : uint32;
+         SizeOfUninitializedData     : uint32;
+         AddressOfEntryPoint         : uint32;
+         BaseOfCode                  : uint32;
+         BaseOfData                  : uint32; --  Note: not in PE32+
+         ImageBase                   : uint32;
+         SectionAlignment            : uint32;
+         FileAlignment               : uint32;
+         MajorOperatingSystemVersion : uint16;
+         MinorOperationSystemVersion : uint16;
+         MajorImageVersion           : uint16;
+         MinorImageVersion           : uint16;
+         MajorSubsystemVersion       : uint16;
+         MinorSubsystemVersion       : uint16;
+         Win32VersionValue           : uint32;
+         SizeOfImage                 : uint32;
+         SizeOfHeaders               : uint32;
+         Checksum                    : uint32;
+         Subsystem                   : uint16;
+         DllCharacteristics          : uint16;
+         SizeOfStackReserve          : uint32;
+         SizeOfStackCommit           : uint32;
+         SizeOfHeapReserve           : uint32;
+         SizeOfHeapCommit            : uint32;
+         LoaderFlags                 : uint32;
+         NumberOfRvaAndSizes         : uint32;
+      end record;
+      pragma Pack (Optional_Header_PE32);
+      pragma Assert (Optional_Header_PE32'Size = 96 * SSU);
+
+      type Optional_Header_PE64 is record
+         Magic                       : uint16;
+         MajorLinkerVersion          : uint8;
+         MinorLinkerVersion          : uint8;
+         SizeOfCode                  : uint32;
+         SizeOfInitializedData       : uint32;
+         SizeOfUninitializedData     : uint32;
+         AddressOfEntryPoint         : uint32;
+         BaseOfCode                  : uint32;
+         ImageBase                   : uint64;
+         SectionAlignment            : uint32;
+         FileAlignment               : uint32;
+         MajorOperatingSystemVersion : uint16;
+         MinorOperationSystemVersion : uint16;
+         MajorImageVersion           : uint16;
+         MinorImageVersion           : uint16;
+         MajorSubsystemVersion       : uint16;
+         MinorSubsystemVersion       : uint16;
+         Win32VersionValue           : uint32;
+         SizeOfImage                 : uint32;
+         SizeOfHeaders               : uint32;
+         Checksum                    : uint32;
+         Subsystem                   : uint16;
+         DllCharacteristics          : uint16;
+         SizeOfStackReserve          : uint64;
+         SizeOfStackCommit           : uint64;
+         SizeOfHeapReserve           : uint64;
+         SizeOfHeapCommit            : uint64;
+         LoaderFlags                 : uint32;
+         NumberOfRvaAndSizes         : uint32;
+      end record;
+      pragma Pack (Optional_Header_PE64);
+      pragma Assert (Optional_Header_PE64'Size = 112 * SSU);
+
+      subtype Name_Str is String (1 .. 8);
+
+      type Section_Header is record
+         Name                 : Name_Str;
+         VirtualSize          : uint32;
+         VirtualAddress       : uint32;
+         SizeOfRawData        : uint32;
+         PointerToRawData     : uint32;
+         PointerToRelocations : uint32;
+         PointerToLinenumbers : uint32;
+         NumberOfRelocations  : uint16;
+         NumberOfLinenumbers  : uint16;
+         Characteristics      : uint32;
+      end record;
+
+      pragma Pack (Section_Header);
+
+      IMAGE_SCN_CNT_CODE : constant := 16#0020#;
+
+      type Symtab_Entry is record
+         Name                  : Name_Str;
+         Value                 : uint32;
+         SectionNumber         : int16;
+         TypeField             : uint16;
+         StorageClass          : uint8;
+         NumberOfAuxSymbols    : uint8;
+      end record;
+
+      pragma Pack (Symtab_Entry);
+
+      type Auxent_Section is record
+         Length              : uint32;
+         NumberOfRelocations : uint16;
+         NumberOfLinenumbers : uint16;
+         CheckSum            : uint32;
+         Number              : uint16;
+         Selection           : uint8;
+         Unused1             : uint8;
+         Unused2             : uint8;
+         Unused3             : uint8;
+      end record;
+
+      for Auxent_Section'Size use 18 * 8;
+
+      function Read_Header (F : in out Mapped_Stream) return Header;
+      --  Read the object file header
+
+      function First_Symbol
+        (Obj : in out PECOFF_Object_File) return Object_Symbol;
+      --  Return the first element in the symbol table, or Null_Symbol if the
+      --  symbol table is empty.
+
+      function Read_Symbol
+        (Obj : in out PECOFF_Object_File;
+         Off : Offset) return Object_Symbol;
+      --  Read a symbol at offset Off
+
+      function Name
+        (Obj : in out PECOFF_Object_File;
+         Sym : Object_Symbol) return String_Ptr_Len;
+      --  Return the name of the symbol
+
+      function Name
+        (Obj : in out PECOFF_Object_File;
+         Sec : Object_Section) return String;
+      --  Return the name of a section
+
+      function Get_Section
+        (Obj   : in out PECOFF_Object_File;
+         Index : uint32) return Object_Section;
+      --  Fetch a section by index from zero
+
+      function Initialize
+        (F            : Mapped_File;
+         Hdr          : Header;
+         In_Exception : Boolean) return PECOFF_Object_File;
+      --  Initialize an object file
+
+   end PECOFF_Ops;
+
+   -------------------------------------
+   -- XCOFF-32 object format handling --
+   -------------------------------------
+
+   package XCOFF32_Ops is
+
+      --  XCOFF Data layout
+
+      type Header is record
+         f_magic  : uint16;
+         f_nscns  : uint16;
+         f_timdat : uint32;
+         f_symptr : uint32;
+         f_nsyms  : uint32;
+         f_opthdr : uint16;
+         f_flags  : uint16;
+      end record;
+
+      type Auxiliary_Header is record
+         o_mflag      : uint16;
+         o_vstamp     : uint16;
+         o_tsize      : uint32;
+         o_dsize      : uint32;
+         o_bsize      : uint32;
+         o_entry      : uint32;
+         o_text_start : uint32;
+         o_data_start : uint32;
+         o_toc        : uint32;
+         o_snentry    : uint16;
+         o_sntext     : uint16;
+         o_sndata     : uint16;
+         o_sntoc      : uint16;
+         o_snloader   : uint16;
+         o_snbss      : uint16;
+         o_algntext   : uint16;
+         o_algndata   : uint16;
+         o_modtype    : uint16;
+         o_cpuflag    : uint8;
+         o_cputype    : uint8;
+         o_maxstack   : uint32;
+         o_maxdata    : uint32;
+         o_debugger   : uint32;
+         o_flags      : uint8;
+         o_sntdata    : uint16;
+         o_sntbss     : uint16;
+      end record;
+      pragma Unreferenced (Auxiliary_Header);
+      --  Not used, but not removed (just in case)
+
+      subtype Name_Str is String (1 .. 8);
+
+      type Section_Header is record
+         s_name    : Name_Str;
+         s_paddr   : uint32;
+         s_vaddr   : uint32;
+         s_size    : uint32;
+         s_scnptr  : uint32;
+         s_relptr  : uint32;
+         s_lnnoptr : uint32;
+         s_nreloc  : uint16;
+         s_nlnno   : uint16;
+         s_flags   : uint32;
+      end record;
+
+      pragma Pack (Section_Header);
+
+      STYP_TEXT : constant := 16#0020#;
+
+      type Symbol_Entry is record
+         n_name   : Name_Str;
+         n_value  : uint32;
+         n_scnum  : uint16;
+         n_type   : uint16;
+         n_sclass : uint8;
+         n_numaux : uint8;
+      end record;
+      for Symbol_Entry'Size use 18 * 8;
+
+      type Aux_Entry is record
+         x_scnlen   : uint32;
+         x_parmhash : uint32;
+         x_snhash   : uint16;
+         x_smtyp    : uint8;
+         x_smclass  : uint8;
+         x_stab     : uint32;
+         x_snstab   : uint16;
+      end record;
+      for Aux_Entry'Size use 18 * 8;
+
+      pragma Pack (Aux_Entry);
+
+      C_EXT     : constant := 2;
+      C_HIDEXT  : constant := 107;
+      C_WEAKEXT : constant := 111;
+
+      XTY_LD : constant := 2;
+      --  Magic constant should be documented, especially since it's changed???
+
+      function Read_Header (F : in out Mapped_Stream) return Header;
+      --  Read the object file header
+
+      function First_Symbol
+        (Obj : in out XCOFF32_Object_File) return Object_Symbol;
+      --  Return the first element in the symbol table, or Null_Symbol if the
+      --  symbol table is empty.
+
+      function Read_Symbol
+        (Obj : in out XCOFF32_Object_File;
+         Off : Offset) return Object_Symbol;
+      --  Read a symbol at offset Off
+
+      function Name
+        (Obj : in out XCOFF32_Object_File;
+         Sym : Object_Symbol) return String_Ptr_Len;
+      --  Return the name of the symbol
+
+      function Name
+        (Obj : in out XCOFF32_Object_File;
+         Sec : Object_Section) return String;
+      --  Return the name of a section
+
+      function Initialize
+        (F            : Mapped_File;
+         Hdr          : Header;
+         In_Exception : Boolean) return XCOFF32_Object_File;
+      --  Initialize an object file
+
+      function Get_Section
+          (Obj   : in out XCOFF32_Object_File;
+           Index : uint32) return Object_Section;
+      --  Fetch a section by index from zero
+
+   end XCOFF32_Ops;
+
+   -------------
+   -- ELF_Ops --
+   -------------
+
+   package body ELF_Ops is
+
+      function Get_String_Table (Obj : in out ELF_Object_File)
+                                return Object_Section;
+      --  Fetch the section containing the string table
+
+      function Get_Symbol_Table (Obj : in out ELF_Object_File)
+                                return Object_Section;
+      --  Fetch the section containing the symbol table
+
+      function Read_Section_Header
+        (Obj   : in out ELF_Object_File;
+         Shnum : uint32) return Section_Header;
+      --  Read the header for an ELF format object section indexed from zero
+
+      ------------------
+      -- First_Symbol --
+      ------------------
+
+      function First_Symbol
+        (Obj : in out ELF_Object_File) return Object_Symbol
+      is
+      begin
+         if Obj.Symtab_Last = 0 then
+            return Null_Symbol;
+         else
+            return Read_Symbol (Obj, 0);
+         end if;
+      end First_Symbol;
+
+      -----------------
+      -- Get_Section --
+      -----------------
+
+      function Get_Section
+        (Obj   : in out ELF_Object_File;
+         Shnum : uint32) return Object_Section
+      is
+         SHdr : constant Section_Header := Read_Section_Header (Obj, Shnum);
+      begin
+         return (Shnum,
+                 Offset (SHdr.Sh_Offset),
+                 uint64 (SHdr.Sh_Addr),
+                 uint64 (SHdr.Sh_Size),
+                 (SHdr.Sh_Flags and SHF_ALLOC) /= 0);
+      end Get_Section;
+
+      ------------------------
+      --  Get_String_Table  --
+      ------------------------
+
+      function Get_String_Table
+        (Obj : in out ELF_Object_File) return Object_Section
+      is
+      begin
+         --  All cases except MIPS IRIX, string table located in .strtab
+
+         if Obj.Arch /= MIPS then
+            return Get_Section (Obj, ".strtab");
+
+         --  On IRIX only .dynstr is available
+
+         else
+            return Get_Section (Obj, ".dynstr");
+         end if;
+      end Get_String_Table;
+
+      ------------------------
+      --  Get_Symbol_Table  --
+      ------------------------
+
+      function Get_Symbol_Table
+        (Obj : in out ELF_Object_File) return Object_Section
+      is
+      begin
+         --  All cases except MIPS IRIX, symbol table located in .symtab
+
+         if Obj.Arch /= MIPS then
+            return Get_Section (Obj, ".symtab");
+
+         --  On IRIX, symbol table located somewhere other than .symtab
+
+         else
+            return Get_Section (Obj, ".dynsym");
+         end if;
+      end Get_Symbol_Table;
+
+      ----------------
+      -- Initialize --
+      ----------------
+
+      function Initialize
+        (F            : Mapped_File;
+         Hdr          : Header;
+         In_Exception : Boolean) return ELF_Object_File
+      is
+         Res : ELF_Object_File
+           (Format => (case uword'Size is
+                         when 64 => ELF64,
+                         when 32 => ELF32,
+                         when others => raise Program_Error));
+         Sec : Object_Section;
+      begin
+         Res.MF := F;
+         Res.In_Exception := In_Exception;
+         Res.Num_Sections := uint32 (Hdr.E_Shnum);
+
+         case Hdr.E_Machine is
+            when EM_SPARC
+               | EM_SPARC32PLUS
+            =>
+               Res.Arch := SPARC;
+
+            when EM_386 =>
+               Res.Arch := i386;
+
+            when EM_MIPS
+               | EM_MIPS_RS3_LE
+            =>
+               Res.Arch := MIPS;
+
+            when EM_PPC =>
+               Res.Arch := PPC;
+
+            when EM_PPC64 =>
+               Res.Arch := PPC64;
+
+            when EM_SPARCV9 =>
+               Res.Arch := SPARC64;
+
+            when EM_IA_64 =>
+               Res.Arch := IA64;
+
+            when EM_X86_64 =>
+               Res.Arch := x86_64;
+
+            when others =>
+               raise Format_Error with "unrecognized architecture";
+         end case;
+
+         --  Map section table and section string table
+         Res.Sectab_Stream := Create_Stream
+           (F, File_Size (Hdr.E_Shoff),
+            File_Size (Hdr.E_Shnum) * File_Size (Hdr.E_Shentsize));
+         Sec := Get_Section (Res, uint32 (Hdr.E_Shstrndx));
+         Res.Secstr_Stream := Create_Stream (Res, Sec);
+
+         --  Map symbol and string table
+         Sec := Get_Symbol_Table (Res);
+         Res.Symtab_Stream := Create_Stream (Res, Sec);
+         Res.Symtab_Last := Offset (Sec.Size);
+
+         Sec := Get_String_Table (Res);
+         Res.Symstr_Stream := Create_Stream (Res, Sec);
+
+         return Res;
+      end Initialize;
+
+      -----------------
+      -- Read_Header --
+      -----------------
+
+      function Read_Header (F : in out Mapped_Stream) return Header is
+         Hdr : Header;
+      begin
+         Seek (F, 0);
+         Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
+         return Hdr;
+      end Read_Header;
+
+      -------------------------
+      -- Read_Section_Header --
+      -------------------------
+
+      function Read_Section_Header
+        (Obj   : in out ELF_Object_File;
+         Shnum : uint32) return Section_Header
+      is
+         Shdr : Section_Header;
+      begin
+         Seek (Obj.Sectab_Stream, Offset (Shnum * Section_Header'Size / SSU));
+         Read_Raw (Obj.Sectab_Stream, Shdr'Address, Section_Header'Size / SSU);
+         return Shdr;
+      end Read_Section_Header;
+
+      -----------------
+      -- Read_Symbol --
+      -----------------
+
+      function Read_Symbol
+        (Obj : in out ELF_Object_File;
+         Off : Offset) return Object_Symbol
+      is
+         ST_Entry32 : Symtab_Entry32;
+         ST_Entry64 : Symtab_Entry64;
+         Res        : Object_Symbol;
+
+      begin
+         Seek (Obj.Symtab_Stream, Off);
+
+         case uword'Size is
+            when 32 =>
+               Read_Raw (Obj.Symtab_Stream, ST_Entry32'Address,
+                         uint32 (ST_Entry32'Size / SSU));
+               Res := (Off,
+                       Off + ST_Entry32'Size / SSU,
+                       uint64 (ST_Entry32.St_Value),
+                       uint64 (ST_Entry32.St_Size));
+
+            when 64 =>
+               Read_Raw (Obj.Symtab_Stream, ST_Entry64'Address,
+                         uint32 (ST_Entry64'Size / SSU));
+               Res := (Off,
+                       Off + ST_Entry64'Size / SSU,
+                       ST_Entry64.St_Value,
+                       ST_Entry64.St_Size);
+
+            when others =>
+               raise Program_Error;
+         end case;
+
+         return Res;
+      end Read_Symbol;
+
+      ----------
+      -- Name --
+      ----------
+
+      function Name
+        (Obj : in out ELF_Object_File;
+         Sec : Object_Section) return String
+      is
+         SHdr : Section_Header;
+      begin
+         SHdr := Read_Section_Header (Obj, Sec.Num);
+         return Offset_To_String (Obj.Secstr_Stream, Offset (SHdr.Sh_Name));
+      end Name;
+
+      function Name
+        (Obj : in out ELF_Object_File;
+         Sym : Object_Symbol) return String_Ptr_Len
+      is
+         ST_Entry32 : Symtab_Entry32;
+         ST_Entry64 : Symtab_Entry64;
+         Name_Off   : Offset;
+
+      begin
+         --  Test that this symbol is not null
+
+         if Sym = Null_Symbol then
+            return (null, 0);
+         end if;
+
+         --  Read the symbol table entry
+
+         Seek (Obj.Symtab_Stream, Sym.Off);
+
+         case uword'Size is
+            when 32 =>
+               Read_Raw (Obj.Symtab_Stream, ST_Entry32'Address,
+                         uint32 (ST_Entry32'Size / SSU));
+               Name_Off := Offset (ST_Entry32.St_Name);
+
+            when 64 =>
+               Read_Raw (Obj.Symtab_Stream, ST_Entry64'Address,
+                         uint32 (ST_Entry64'Size / SSU));
+               Name_Off := Offset (ST_Entry64.St_Name);
+
+            when others =>
+               raise Program_Error;
+         end case;
+
+         --  Fetch the name from the string table
+
+         Seek (Obj.Symstr_Stream, Name_Off);
+         return Read (Obj.Symstr_Stream);
+      end Name;
+
+   end ELF_Ops;
+
+   package ELF32_Ops is new ELF_Ops (uint32);
+   package ELF64_Ops is new ELF_Ops (uint64);
+
+   ----------------
+   -- PECOFF_Ops --
+   ----------------
+
+   package body PECOFF_Ops is
+
+      function Decode_Name
+        (Obj      : in out PECOFF_Object_File;
+         Raw_Name : String) return String;
+      --  A section name is an 8 byte field padded on the right with null
+      --  characters, or a '\' followed by an ASCII decimal string indicating
+      --  an offset in to the string table. This routine decodes this
+
+      function Get_Section_Virtual_Address
+        (Obj   : in out PECOFF_Object_File;
+         Index : uint32) return uint64;
+      --  Fetch the address at which a section is loaded
+
+      function Read_Section_Header
+        (Obj   : in out PECOFF_Object_File;
+         Index : uint32) return Section_Header;
+      --  Read a header from section table
+
+      function String_Table
+        (Obj   : in out PECOFF_Object_File;
+         Index : Offset) return String;
+      --  Return an entry from the string table
+
+      -----------------
+      -- Decode_Name --
+      -----------------
+
+      function Decode_Name
+        (Obj      : in out PECOFF_Object_File;
+         Raw_Name : String) return String
+      is
+         Name_Or_Ref : constant String := Trim_Trailing_Nuls (Raw_Name);
+         Off         : Offset;
+
+      begin
+         --  We should never find a symbol with a zero length name. If we do it
+         --  probably means we are not parsing the symbol table correctly. If
+         --  this happens we raise a fatal error.
+
+         if Name_Or_Ref'Length = 0 then
+            raise Format_Error with
+              "found zero length symbol in symbol table";
+         end if;
+
+         if Name_Or_Ref (1) /= '/' then
+            return Name_Or_Ref;
+         else
+            Off := Offset'Value (Name_Or_Ref (2 .. Name_Or_Ref'Last));
+            return String_Table (Obj, Off);
+         end if;
+      end Decode_Name;
+
+      ------------------
+      -- First_Symbol --
+      ------------------
+
+      function First_Symbol
+        (Obj : in out PECOFF_Object_File) return Object_Symbol is
+      begin
+         --  Return Null_Symbol in the case that the symbol table is empty
+
+         if Obj.Symtab_Last = 0 then
+            return Null_Symbol;
+         end if;
+
+         return Read_Symbol (Obj, 0);
+      end First_Symbol;
+
+      -----------------
+      -- Get_Section --
+      -----------------
+
+      function Get_Section
+        (Obj   : in out PECOFF_Object_File;
+         Index : uint32) return Object_Section
+      is
+         Sec : constant Section_Header := Read_Section_Header (Obj, Index);
+      begin
+         --  Use VirtualSize instead of SizeOfRawData. The latter is rounded to
+         --  the page size, so it may add garbage to the content. On the other
+         --  side, the former may be larger than the latter in case of 0
+         --  padding.
+
+         return (Index,
+                 Offset (Sec.PointerToRawData),
+                 uint64 (Sec.VirtualAddress) + Obj.ImageBase,
+                 uint64 (Sec.VirtualSize),
+                 (Sec.Characteristics and IMAGE_SCN_CNT_CODE) /= 0);
+      end Get_Section;
+
+      ---------------------------------
+      -- Get_Section_Virtual_Address --
+      ---------------------------------
+
+      function Get_Section_Virtual_Address
+        (Obj   : in out PECOFF_Object_File;
+         Index : uint32) return uint64
+      is
+         Sec : Section_Header;
+
+      begin
+         --  Try cache
+
+         if Index = Obj.GSVA_Sec then
+            return Obj.GSVA_Addr;
+         end if;
+
+         Obj.GSVA_Sec := Index;
+         Sec := Read_Section_Header (Obj, Index);
+         Obj.GSVA_Addr := Obj.ImageBase + uint64 (Sec.VirtualAddress);
+         return Obj.GSVA_Addr;
+      end Get_Section_Virtual_Address;
+
+      ----------------
+      -- Initialize --
+      ----------------
+
+      function Initialize
+        (F            : Mapped_File;
+         Hdr          : Header;
+         In_Exception : Boolean) return PECOFF_Object_File
+      is
+         Res        : PECOFF_Object_File
+           (Format => (case Hdr.Variant is
+                         when PECOFF_Ops.VARIANT_PE32 => PECOFF,
+                         when PECOFF_Ops.VARIANT_PE32_PLUS => PECOFF_PLUS,
+                         when others => raise Program_Error
+                                          with "unrecognized PECOFF variant"));
+         Symtab_Size : constant Offset :=
+           Offset (Hdr.NumberOfSymbols) * (Symtab_Entry'Size / SSU);
+         Strtab_Size : uint32;
+         Hdr_Offset : Offset;
+         Opt_Offset : File_Size;
+         Opt_Stream : Mapped_Stream;
+      begin
+         Res.MF := F;
+         Res.In_Exception := In_Exception;
+
+         case Hdr.Machine is
+            when PECOFF_Ops.IMAGE_FILE_MACHINE_I386  =>
+               Res.Arch := i386;
+            when PECOFF_Ops.IMAGE_FILE_MACHINE_IA64  =>
+               Res.Arch := IA64;
+            when PECOFF_Ops.IMAGE_FILE_MACHINE_AMD64 =>
+               Res.Arch := x86_64;
+            when others =>
+               raise Format_Error with "unrecognized architecture";
+         end case;
+
+         Res.Num_Sections := uint32 (Hdr.NumberOfSections);
+
+         --  Map symbol table and the first following word (which is the length
+         --  of the string table).
+
+         Res.Symtab_Last  := Symtab_Size;
+         Res.Symtab_Stream := Create_Stream
+           (F,
+            File_Size (Hdr.PointerToSymbolTable),
+            File_Size (Symtab_Size + 4));
+
+         --  Map string table. The first 4 bytes are the length of the string
+         --  table and are part of it.
+
+         Seek (Res.Symtab_Stream, Symtab_Size);
+         Strtab_Size := Read (Res.Symtab_Stream);
+         Res.Symstr_Stream := Create_Stream
+           (F,
+            File_Size (Hdr.PointerToSymbolTable) + File_Size (Symtab_Size),
+            File_Size (Strtab_Size));
+
+         --  Map section table
+
+         Opt_Stream := Create_Stream (Res.Mf, Signature_Loc_Offset, 4);
+         Hdr_Offset := Offset (uint32'(Read (Opt_Stream)));
+         Close (Opt_Stream);
+         Res.Sectab_Stream := Create_Stream
+           (F,
+            File_Size (Hdr_Offset +
+                         Size_Of_Standard_Header_Fields +
+                         Offset (Hdr.SizeOfOptionalHeader)),
+            File_Size (Res.Num_Sections)
+              * File_Size (Section_Header'Size / SSU));
+
+         --  Read optional header and extract image base
+
+         Opt_Offset := File_Size (Hdr_Offset + Size_Of_Standard_Header_Fields);
+
+         if Res.Format = PECOFF then
+            declare
+               Opt_32 : Optional_Header_PE32;
+            begin
+               Opt_Stream := Create_Stream
+                 (Res.Mf, Opt_Offset, Opt_32'Size / SSU);
+               Read_Raw
+                 (Opt_Stream, Opt_32'Address, uint32 (Opt_32'Size / SSU));
+               Res.ImageBase := uint64 (Opt_32.ImageBase);
+               Close (Opt_Stream);
+            end;
+
+         else
+            declare
+               Opt_64 : Optional_Header_PE64;
+            begin
+               Opt_Stream := Create_Stream
+                 (Res.Mf, Opt_Offset, Opt_64'Size / SSU);
+               Read_Raw
+                 (Opt_Stream, Opt_64'Address, uint32 (Opt_64'Size / SSU));
+               Res.ImageBase := Opt_64.ImageBase;
+               Close (Opt_Stream);
+            end;
+         end if;
+
+         return Res;
+      end Initialize;
+
+      -----------------
+      -- Read_Symbol --
+      -----------------
+
+      function Read_Symbol
+        (Obj : in out PECOFF_Object_File;
+         Off : Offset) return Object_Symbol
+      is
+         ST_Entry  : Symtab_Entry;
+         ST_Last   : Symtab_Entry;
+         Aux_Entry : Auxent_Section;
+         Sz        : constant Offset := ST_Entry'Size / SSU;
+         Result    : Object_Symbol;
+         Noff      : Offset;
+         Sym_Off   : Offset;
+
+      begin
+         --  Seek to the successor of Prev
+
+         Noff := Off;
+
+         loop
+            Sym_Off := Noff;
+
+            Seek (Obj.Symtab_Stream, Sym_Off);
+            Read_Raw (Obj.Symtab_Stream, ST_Entry'Address, uint32 (Sz));
+
+            --  Skip AUX entries
+
+            Noff := Noff + Offset (1 + ST_Entry.NumberOfAuxSymbols) * Sz;
+
+            exit when ST_Entry.TypeField = Function_Symbol_Type
+              and then ST_Entry.SectionNumber > 0;
+
+            if Noff >= Obj.Symtab_Last then
+               return Null_Symbol;
+            end if;
+         end loop;
+
+         --  Construct the symbol
+
+         Result :=
+           (Off   => Sym_Off,
+            Next  => Noff,
+            Value => uint64 (ST_Entry.Value),
+            Size  => 0);
+
+         --  Set the size as accurately as possible
+
+         --  The size of a symbol is not directly available so we try scanning
+         --  to the next function and assuming the code ends there.
+
+         loop
+            --  Read symbol and AUX entries
+
+            Sym_Off := Noff;
+            Seek (Obj.Symtab_Stream, Sym_Off);
+            Read_Raw (Obj.Symtab_Stream, ST_Last'Address, uint32 (Sz));
+
+            for I in 1 .. ST_Last.NumberOfAuxSymbols loop
+               Read_Raw (Obj.Symtab_Stream, Aux_Entry'Address, uint32 (Sz));
+            end loop;
+
+            Noff := Noff + Offset (1 + ST_Last.NumberOfAuxSymbols) * Sz;
+
+            if ST_Last.TypeField = Function_Symbol_Type then
+               if ST_Last.SectionNumber = ST_Entry.SectionNumber
+                 and then ST_Last.Value >= ST_Entry.Value
+               then
+                  --  Symbol is a function past ST_Entry
+
+                  Result.Size := uint64 (ST_Last.Value - ST_Entry.Value);
+
+               else
+                  --  Not correlated function
+
+                  Result.Next := Sym_Off;
+               end if;
+
+               exit;
+
+            elsif ST_Last.SectionNumber = ST_Entry.SectionNumber
+              and then ST_Last.TypeField = Not_Function_Symbol_Type
+              and then ST_Last.StorageClass = 3
+              and then ST_Last.NumberOfAuxSymbols = 1
+            then
+               --  Symbol is a section
+
+               Result.Size := uint64 (ST_Last.Value + Aux_Entry.Length
+                                        - ST_Entry.Value);
+               Result.Next := Noff;
+               exit;
+            end if;
+
+            exit when Noff >= Obj.Symtab_Last;
+         end loop;
+
+         --  Relocate the address
+
+         Result.Value :=
+           Result.Value + Get_Section_Virtual_Address
+                            (Obj, uint32 (ST_Entry.SectionNumber - 1));
+
+         return Result;
+      end Read_Symbol;
+
+      ------------------
+      -- Read_Header  --
+      ------------------
+
+      function Read_Header (F : in out Mapped_Stream) return Header is
+         Hdr : Header;
+         Off : int32;
+
+      begin
+         --  Skip the MSDOS stub, and seek directly to the file offset
+
+         Seek (F, Signature_Loc_Offset);
+         Off := Read (F);
+
+         --  Read the COFF file header
+
+         Seek (F, Offset (Off));
+         Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
+         return Hdr;
+      end Read_Header;
+
+      -------------------------
+      -- Read_Section_Header --
+      -------------------------
+
+      function Read_Section_Header
+        (Obj   : in out PECOFF_Object_File;
+         Index : uint32) return Section_Header
+      is
+         Sec : Section_Header;
+      begin
+         Seek (Obj.Sectab_Stream, Offset (Index * Section_Header'Size / SSU));
+         Read_Raw (Obj.Sectab_Stream, Sec'Address, Section_Header'Size / SSU);
+         return Sec;
+      end Read_Section_Header;
+
+      ----------
+      -- Name --
+      ----------
+
+      function Name
+        (Obj : in out PECOFF_Object_File;
+         Sec : Object_Section) return String
+      is
+         Shdr : constant Section_Header := Read_Section_Header (Obj, Sec.Num);
+      begin
+         return Decode_Name (Obj, Shdr.Name);
+      end Name;
+
+      -------------------
+      -- String_Table  --
+      -------------------
+
+      function String_Table
+        (Obj   : in out PECOFF_Object_File;
+         Index : Offset) return String is
+      begin
+         --  An index of zero is used to represent an empty string, as the
+         --  first word of the string table is specified to contain the length
+         --  of the table rather than its contents.
+
+         if Index = 0 then
+            return "";
+
+         else
+            return Offset_To_String (Obj.Symstr_Stream, Index);
+         end if;
+      end String_Table;
+
+      ----------
+      -- Name --
+      ----------
+
+      function Name
+        (Obj : in out PECOFF_Object_File;
+         Sym : Object_Symbol) return String_Ptr_Len
+      is
+         ST_Entry : Symtab_Entry;
+
+      begin
+         Seek (Obj.Symtab_Stream, Sym.Off);
+         Read_Raw (Obj.Symtab_Stream, ST_Entry'Address, ST_Entry'Size / SSU);
+
+         declare
+            --  Symbol table entries are packed and Table_Entry.Name may not be
+            --  sufficiently aligned to interpret as a 32 bit word, so it is
+            --  copied to a temporary
+
+            Aligned_Name : Name_Str := ST_Entry.Name;
+            for Aligned_Name'Alignment use 4;
+
+            First_Word : uint32;
+            pragma Import (Ada, First_Word);
+            --  Suppress initialization in Normalized_Scalars mode
+            for First_Word'Address use Aligned_Name (1)'Address;
+
+            Second_Word : uint32;
+            pragma Import (Ada, Second_Word);
+            --  Suppress initialization in Normalized_Scalars mode
+            for Second_Word'Address use Aligned_Name (5)'Address;
+
+         begin
+            if First_Word = 0 then
+               --  Second word is an offset in the symbol table
+               if Second_Word = 0 then
+                  return (null, 0);
+               else
+                  Seek (Obj.Symstr_Stream, int64 (Second_Word));
+                  return Read (Obj.Symstr_Stream);
+               end if;
+            else
+               --  Inlined symbol name
+               Seek (Obj.Symtab_Stream, Sym.Off);
+               return To_String_Ptr_Len (Read (Obj.Symtab_Stream), 8);
+            end if;
+         end;
+      end Name;
+
+   end PECOFF_Ops;
+
+   -----------------
+   -- XCOFF32_Ops --
+   -----------------
+
+   package body XCOFF32_Ops is
+
+      function Read_Section_Header
+        (Obj   : in out XCOFF32_Object_File;
+         Index : uint32) return Section_Header;
+      --  Read a header from section table
+
+      -----------------
+      -- Read_Symbol --
+      -----------------
+
+      function Read_Symbol
+        (Obj : in out XCOFF32_Object_File;
+         Off : Offset) return Object_Symbol
+      is
+         Sym     : Symbol_Entry;
+         Sz      : constant Offset := Symbol_Entry'Size / SSU;
+         Aux     : Aux_Entry;
+         Result  : Object_Symbol;
+         Noff    : Offset;
+         Sym_Off : Offset;
+
+         procedure Read_LD_Symbol;
+         --  Read the next LD symbol
+
+         --------------------
+         -- Read_LD_Symbol --
+         --------------------
+
+         procedure Read_LD_Symbol is
+         begin
+            loop
+               Sym_Off := Noff;
+
+               Read_Raw (Obj.Symtab_Stream, Sym'Address, uint32 (Sz));
+
+               Noff := Noff + Offset (1 + Sym.n_numaux) * Sz;
+
+               for J in 1 .. Sym.n_numaux loop
+                  Read_Raw (Obj.Symtab_Stream, Aux'Address, uint32 (Sz));
+               end loop;
+
+               exit when Noff >= Obj.Symtab_Last;
+
+               exit when Sym.n_numaux = 1
+                 and then Sym.n_scnum /= 0
+                 and then (Sym.n_sclass = C_EXT
+                           or else Sym.n_sclass = C_HIDEXT
+                           or else Sym.n_sclass = C_WEAKEXT)
+                 and then Aux.x_smtyp = XTY_LD;
+            end loop;
+         end Read_LD_Symbol;
+
+      --  Start of processing for Read_Symbol
+
+      begin
+         Seek (Obj.Symtab_Stream, Off);
+         Noff := Off;
+         Read_LD_Symbol;
+
+         if Noff >= Obj.Symtab_Last then
+            return Null_Symbol;
+         end if;
+
+         --  Construct the symbol
+
+         Result := (Off   => Sym_Off,
+                    Next  => Noff,
+                    Value => uint64 (Sym.n_value),
+                    Size  => 0);
+
+         --  Look for the next symbol to compute the size
+
+         Read_LD_Symbol;
+
+         if Noff >= Obj.Symtab_Last then
+            return Null_Symbol;
+         end if;
+
+         Result.Size := uint64 (Sym.n_value) - Result.Value;
+         Result.Next := Sym_Off;
+         return Result;
+      end Read_Symbol;
+
+      ------------------
+      -- First_Symbol --
+      ------------------
+
+      function First_Symbol
+        (Obj : in out XCOFF32_Object_File) return Object_Symbol
+      is
+      begin
+         --  Return Null_Symbol in the case that the symbol table is empty
+
+         if Obj.Symtab_Last = 0 then
+            return Null_Symbol;
+         end if;
+
+         return Read_Symbol (Obj, 0);
+      end First_Symbol;
+
+      ----------------
+      -- Initialize --
+      ----------------
+
+      function Initialize
+        (F            : Mapped_File;
+         Hdr          : Header;
+         In_Exception : Boolean) return XCOFF32_Object_File
+      is
+         Res : XCOFF32_Object_File (Format => XCOFF32);
+         Strtab_Sz : uint32;
+      begin
+         Res.Mf := F;
+         Res.In_Exception := In_Exception;
+
+         Res.Arch := PPC;
+
+         --  Map sections table
+         Res.Num_Sections := uint32 (Hdr.f_nscns);
+         Res.Sectab_Stream := Create_Stream
+           (F,
+            File_Size (Header'Size / SSU) + File_Size (Hdr.f_opthdr),
+            File_Size (Hdr.f_nscns) * (Section_Header'Size / SSU));
+
+         --  Map symbols table
+         Res.Symtab_Last := Offset (Hdr.f_nscns) * (Symbol_Entry'Size / SSU);
+         Res.Symtab_Stream := Create_Stream
+           (F,
+            File_Size (Hdr.f_symptr),
+            File_Size (Res.Symtab_Last) + 4);
+
+         --  Map string table
+         Seek (Res.Symtab_Stream, Res.Symtab_Last);
+         Strtab_Sz := Read (Res.Symtab_Stream);
+         Res.Symstr_Stream := Create_Stream
+           (F,
+            File_Size (Res.Symtab_Last) + 4,
+            File_Size (Strtab_Sz) - 4);
+
+         return Res;
+      end Initialize;
+
+      -----------------
+      -- Get_Section --
+      -----------------
+
+      function Get_Section
+        (Obj   : in out XCOFF32_Object_File;
+         Index : uint32) return Object_Section
+      is
+         Sec : constant Section_Header := Read_Section_Header (Obj, Index);
+      begin
+         return (Index, Offset (Sec.s_scnptr),
+                 uint64 (Sec.s_vaddr),
+                 uint64 (Sec.s_size),
+                 (Sec.s_flags and STYP_TEXT) /= 0);
+      end Get_Section;
+
+      -----------------
+      -- Read_Header --
+      -----------------
+
+      function Read_Header (F : in out Mapped_Stream) return Header is
+         Hdr : Header;
+      begin
+         Seek (F, 0);
+         Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
+         return Hdr;
+      end Read_Header;
+
+      -------------------------
+      -- Read_Section_Header --
+      -------------------------
+
+      function Read_Section_Header
+        (Obj   : in out XCOFF32_Object_File;
+         Index : uint32) return Section_Header
+      is
+         Sec     : Section_Header;
+
+      begin
+         --  Seek to the end of the object header
+
+         Seek (Obj.Sectab_Stream, Offset (Index * Section_Header'Size / SSU));
+
+         --  Read the section
+
+         Read_Raw (Obj.Sectab_Stream, Sec'Address, Section_Header'Size / SSU);
+
+         return Sec;
+      end Read_Section_Header;
+
+      ----------
+      -- Name --
+      ----------
+
+      function Name
+        (Obj : in out XCOFF32_Object_File;
+         Sec : Object_Section) return String
+      is
+         Hdr : Section_Header;
+      begin
+         Hdr := Read_Section_Header (Obj, Sec.Num);
+         return Trim_Trailing_Nuls (Hdr.s_name);
+      end Name;
+
+      ----------
+      -- Name --
+      ----------
+
+      function Name
+        (Obj : in out XCOFF32_Object_File;
+         Sym : Object_Symbol) return String_Ptr_Len
+      is
+         Symbol  : Symbol_Entry;
+
+      begin
+         Seek (Obj.Symtab_Stream, Sym.Off);
+         Read_Raw (Obj.Symtab_Stream, Symbol'Address, Symbol'Size / SSU);
+
+         declare
+            First_Word : uint32;
+            pragma Import (Ada, First_Word);
+            --  Suppress initialization in Normalized_Scalars mode
+            for First_Word'Address use Symbol.n_name (1)'Address;
+
+            Second_Word : uint32;
+            pragma Import (Ada, Second_Word);
+            --  Suppress initialization in Normalized_Scalars mode
+            for Second_Word'Address use Symbol.n_name (5)'Address;
+
+         begin
+            if First_Word = 0 then
+               if Second_Word = 0 then
+                  return (null, 0);
+               else
+                  Seek (Obj.Symstr_Stream, int64 (Second_Word));
+                  return Read (Obj.Symstr_Stream);
+               end if;
+            else
+               Seek (Obj.Symtab_Stream, Sym.Off);
+               return To_String_Ptr_Len (Read (Obj.Symstr_Stream), 8);
+            end if;
+         end;
+      end Name;
+   end XCOFF32_Ops;
+
+   ----------
+   -- Arch --
+   ----------
+
+   function Arch (Obj : Object_File) return Object_Arch is
+   begin
+      return Obj.Arch;
+   end Arch;
+
+   function Create_Stream
+     (Mf : Mapped_File;
+      File_Offset : File_Size;
+      File_Length : File_Size)
+     return Mapped_Stream
+   is
+      Region : Mapped_Region;
+   begin
+      Read (Mf, Region, File_Offset, File_Length, False);
+      return (Region, 0, Offset (File_Length));
+   end Create_Stream;
+
+   function Create_Stream
+     (Obj : Object_File;
+      Sec : Object_Section) return Mapped_Stream is
+   begin
+      return Create_Stream (Obj.Mf, File_Size (Sec.Off), File_Size (Sec.Size));
+   end Create_Stream;
+
+   procedure Tell (Obj : in out Mapped_Stream; Off : out Offset) is
+   begin
+      Off := Obj.Off;
+   end Tell;
+
+   function Tell (Obj : Mapped_Stream) return Offset is
+   begin
+      return Obj.Off;
+   end Tell;
+
+   function Length (Obj : Mapped_Stream) return Offset is
+   begin
+      return Obj.Len;
+   end Length;
+
+   -----------
+   -- Close --
+   -----------
+
+   procedure Close (S : in out Mapped_Stream) is
+   begin
+      Free (S.Region);
+   end Close;
+
+   procedure Close (Obj : in out Object_File) is
+   begin
+      Close (Obj.Symtab_Stream);
+      Close (Obj.Symstr_Stream);
+      Close (Obj.Sectab_Stream);
+
+      case Obj.Format is
+         when ELF =>
+            Close (Obj.Secstr_Stream);
+         when Any_PECOFF =>
+            null;
+         when XCOFF32 =>
+            null;
+      end case;
+
+      Close (Obj.Mf);
+   end Close;
+
+   ------------------------
+   -- Strip_Leading_Char --
+   ------------------------
+
+   function Strip_Leading_Char
+     (Obj : in out Object_File;
+      Sym : String_Ptr_Len) return Positive is
+   begin
+      if (Obj.Format = PECOFF  and then Sym.Ptr (1) = '_')
+        or else
+        (Obj.Format = XCOFF32 and then Sym.Ptr (1) = '.')
+      then
+         return 2;
+      else
+         return 1;
+      end if;
+   end Strip_Leading_Char;
+
+   ----------------------
+   -- Decoded_Ada_Name --
+   ----------------------
+
+   function Decoded_Ada_Name
+     (Obj : in out Object_File;
+      Sym : String_Ptr_Len) return String
+   is
+      procedure gnat_decode
+        (Coded_Name_Addr : Address;
+         Ada_Name_Addr   : Address;
+         Verbose         : int);
+      pragma Import (C, gnat_decode, "__gnat_decode");
+
+      subtype size_t is Interfaces.C.size_t;
+
+      Sym_Name : constant String :=
+        String (Sym.Ptr (1 .. Sym.Len)) & ASCII.NUL;
+      Decoded : char_array (0 .. size_t (Sym.Len) * 2 + 60);
+      Off     : Natural;
+   begin
+      --  In the PECOFF case most but not all symbol table entries have an
+      --  extra leading underscore. In this case we trim it.
+
+      Off := Strip_Leading_Char (Obj, Sym);
+
+      gnat_decode (Sym_Name (Off)'Address, Decoded'Address, 0);
+
+      return To_Ada (Decoded);
+   end Decoded_Ada_Name;
+
+   ------------------
+   -- First_Symbol --
+   ------------------
+
+   function First_Symbol (Obj : in out Object_File) return Object_Symbol is
+   begin
+      case Obj.Format is
+         when ELF32      => return ELF32_Ops.First_Symbol   (Obj);
+         when ELF64      => return ELF64_Ops.First_Symbol   (Obj);
+         when Any_PECOFF => return PECOFF_Ops.First_Symbol  (Obj);
+         when XCOFF32    => return XCOFF32_Ops.First_Symbol (Obj);
+      end case;
+   end First_Symbol;
+
+   ------------
+   -- Format --
+   ------------
+
+   function Format (Obj : Object_File) return Object_Format is
+   begin
+      return Obj.Format;
+   end Format;
+
+   ----------------------
+   -- Get_Load_Address --
+   ----------------------
+
+   function Get_Load_Address (Obj : Object_File) return uint64 is
+   begin
+      raise Format_Error with "Get_Load_Address not implemented";
+      return 0;
+   end Get_Load_Address;
+
+   -----------------
+   -- Get_Section --
+   -----------------
+
+   function Get_Section
+     (Obj   : in out Object_File;
+      Shnum : uint32) return Object_Section is
+   begin
+      case Obj.Format is
+         when ELF32      => return ELF32_Ops.Get_Section   (Obj, Shnum);
+         when ELF64      => return ELF64_Ops.Get_Section   (Obj, Shnum);
+         when Any_PECOFF => return PECOFF_Ops.Get_Section  (Obj, Shnum);
+         when XCOFF32    => return XCOFF32_Ops.Get_Section (Obj, Shnum);
+      end case;
+   end Get_Section;
+
+   function Get_Section
+     (Obj      : in out Object_File;
+      Sec_Name : String) return Object_Section
+   is
+      Sec : Object_Section;
+
+   begin
+      for J in 0 .. Obj.Num_Sections - 1 loop
+         Sec := Get_Section (Obj, J);
+
+         if Name (Obj, Sec) = Sec_Name then
+            return Sec;
+         end if;
+      end loop;
+
+      if Obj.In_Exception then
+         return Null_Section;
+      else
+         raise Format_Error with "could not find section in object file";
+      end if;
+   end Get_Section;
+
+   -----------------------
+   -- Get_Memory_Bounds --
+   -----------------------
+
+   procedure Get_Memory_Bounds
+     (Obj   : in out Object_File;
+      Low, High : out uint64) is
+      Sec : Object_Section;
+   begin
+      --  First set as an empty range
+      Low := uint64'Last;
+      High := uint64'First;
+
+      for Idx in 1 .. Num_Sections (Obj) loop
+         Sec := Get_Section (Obj, Idx - 1);
+         if Sec.Flag_Alloc then
+            if Sec.Addr < Low then
+               Low := Sec.Addr;
+            end if;
+            if Sec.Addr + Sec.Size > High then
+               High := Sec.Addr + Sec.Size;
+            end if;
+         end if;
+      end loop;
+   end Get_Memory_Bounds;
+
+   ----------
+   -- Name --
+   ----------
+
+   function Name
+     (Obj : in out Object_File;
+      Sec : Object_Section) return String is
+   begin
+      case Obj.Format is
+         when ELF32      => return ELF32_Ops.Name   (Obj, Sec);
+         when ELF64      => return ELF64_Ops.Name   (Obj, Sec);
+         when Any_PECOFF => return PECOFF_Ops.Name  (Obj, Sec);
+         when XCOFF32    => return XCOFF32_Ops.Name (Obj, Sec);
+      end case;
+   end Name;
+
+   function Name
+     (Obj : in out Object_File;
+      Sym : Object_Symbol) return String_Ptr_Len is
+   begin
+      case Obj.Format is
+         when ELF32      => return ELF32_Ops.Name   (Obj, Sym);
+         when ELF64      => return ELF64_Ops.Name   (Obj, Sym);
+         when Any_PECOFF => return PECOFF_Ops.Name  (Obj, Sym);
+         when XCOFF32    => return XCOFF32_Ops.Name (Obj, Sym);
+      end case;
+   end Name;
+
+   -----------------
+   -- Next_Symbol --
+   -----------------
+
+   function Next_Symbol
+     (Obj  : in out Object_File;
+      Prev : Object_Symbol) return Object_Symbol is
+   begin
+      --  Test whether we've reached the end of the symbol table
+
+      if Prev.Next >= Obj.Symtab_Last then
+         return Null_Symbol;
+      end if;
+
+      return Read_Symbol (Obj, Prev.Next);
+   end Next_Symbol;
+
+   ---------
+   -- Num --
+   ---------
+
+   function Num (Sec : Object_Section) return uint32 is
+   begin
+      return Sec.Num;
+   end Num;
+
+   ------------------
+   -- Num_Sections --
+   ------------------
+
+   function Num_Sections (Obj : Object_File) return uint32 is
+   begin
+      return Obj.Num_Sections;
+   end Num_Sections;
+
+   ---------
+   -- Off --
+   ---------
+
+   function Off (Sec : Object_Section) return Offset is
+   begin
+      return Sec.Off;
+   end Off;
+
+   function Off (Sym : Object_Symbol) return Offset is
+   begin
+      return Sym.Off;
+   end Off;
+
+   ----------------------
+   -- Offset_To_String --
+   ----------------------
+
+   function Offset_To_String
+     (S : in out Mapped_Stream;
+      Off : Offset) return String
+   is
+      Buf     : Buffer;
+   begin
+      Seek (S, Off);
+      Read_C_String (S, Buf);
+      return To_String (Buf);
+   end Offset_To_String;
+
+   ----------
+   -- Open --
+   ----------
+
+   function Open
+     (File_Name    : String;
+      In_Exception : Boolean := False) return Object_File_Access
+   is
+      F          : Mapped_File;
+      Hdr_Stream : Mapped_Stream;
+
+   begin
+      --  Open the file
+
+      F := Open_Read_No_Exception (File_Name);
+
+      if F = Invalid_Mapped_File then
+         if In_Exception then
+            return null;
+         else
+            raise IO_Error with "could not open object file";
+         end if;
+      end if;
+
+      Hdr_Stream := Create_Stream (F, 0, 4096);
+
+      declare
+         Hdr : constant ELF32_Ops.Header := ELF32_Ops.Read_Header (Hdr_Stream);
+
+      begin
+         --  Look for the magic numbers for the ELF case
+
+         if Hdr.E_Ident (0) = 16#7F#              and then
+            Hdr.E_Ident (1) = Character'Pos ('E') and then
+            Hdr.E_Ident (2) = Character'Pos ('L') and then
+            Hdr.E_Ident (3) = Character'Pos ('F') and then
+            Hdr.E_Ident (4) = ELF32_Ops.ELFCLASS32
+         then
+            Close (Hdr_Stream);
+            return new Object_File'
+                  (ELF32_Ops.Initialize (F, Hdr, In_Exception));
+         end if;
+      end;
+
+      declare
+         Hdr : constant ELF64_Ops.Header :=
+           ELF64_Ops.Read_Header (Hdr_Stream);
+
+      begin
+         --  Look for the magic numbers for the ELF case
+
+         if Hdr.E_Ident (0) = 16#7F#              and then
+            Hdr.E_Ident (1) = Character'Pos ('E') and then
+            Hdr.E_Ident (2) = Character'Pos ('L') and then
+            Hdr.E_Ident (3) = Character'Pos ('F') and then
+            Hdr.E_Ident (4) = ELF32_Ops.ELFCLASS64
+         then
+            Close (Hdr_Stream);
+            return new Object_File'
+                         (ELF64_Ops.Initialize (F, Hdr, In_Exception));
+         end if;
+      end;
+
+      declare
+         Hdr : constant PECOFF_Ops.Header :=
+           PECOFF_Ops.Read_Header (Hdr_Stream);
+
+      begin
+         --  Test the magic numbers
+
+         if Hdr.Magics (0) = Character'Pos ('P') and then
+            Hdr.Magics (1) = Character'Pos ('E') and then
+            Hdr.Magics (2) = 0                   and then
+            Hdr.Magics (3) = 0
+         then
+            Close (Hdr_Stream);
+            return new Object_File'
+                         (PECOFF_Ops.Initialize (F, Hdr, In_Exception));
+         end if;
+
+      exception
+         --  If this is not a PECOFF file then we've done a seek and read to a
+         --  random address, possibly raising IO_Error
+
+         when IO_Error =>
+            null;
+      end;
+
+      declare
+         Hdr : constant XCOFF32_Ops.Header :=
+           XCOFF32_Ops.Read_Header (Hdr_Stream);
+
+      begin
+         --  Test the magic numbers
+
+         if Hdr.f_magic = 8#0737# then
+            Close (Hdr_Stream);
+            return new Object_File'
+                         (XCOFF32_Ops.Initialize (F, Hdr, In_Exception));
+         end if;
+      end;
+
+      Close (Hdr_Stream);
+
+      if In_Exception then
+         return null;
+      else
+         raise Format_Error with "unrecognized object format";
+      end if;
+   end Open;
+
+   ----------
+   -- Read --
+   ----------
+
+   function Read (S : in out Mapped_Stream) return Mmap.Str_Access
+   is
+      function To_Str_Access is
+         new Ada.Unchecked_Conversion (Address, Str_Access);
+   begin
+      return To_Str_Access (Data (S.Region) (Natural (S.Off + 1))'Address);
+   end Read;
+
+   function Read (S : in out Mapped_Stream) return String_Ptr_Len is
+   begin
+      return To_String_Ptr_Len (Read (S));
+   end Read;
+
+   procedure Check_Read_Offset (S : in out Mapped_Stream; Size : uint32) is
+   begin
+      if S.Off + Offset (Size) > Offset (Last (S.Region)) then
+         raise IO_Error with "could not read from object file";
+      end if;
+   end Check_Read_Offset;
+
+   procedure Read_Raw
+     (S    : in out Mapped_Stream;
+      Addr : Address;
+      Size : uint32)
+   is
+      function To_Str_Access is
+         new Ada.Unchecked_Conversion (Address, Str_Access);
+
+      Sz : constant Offset := Offset (Size);
+   begin
+      --  Check size
+
+      pragma Debug (Check_Read_Offset (S, Size));
+
+      --  Copy data
+
+      To_Str_Access (Addr) (1 .. Positive (Sz)) :=
+        Data (S.Region) (Positive (S.Off + 1) .. Positive (S.Off + Sz));
+
+      --  Update offset
+
+      S.Off := S.Off + Sz;
+   end Read_Raw;
+
+   function Read (S : in out Mapped_Stream) return uint8 is
+      Data : uint8;
+   begin
+      Read_Raw (S, Data'Address, Data'Size / SSU);
+      return Data;
+   end Read;
+
+   function Read (S : in out Mapped_Stream) return uint16 is
+      Data : uint16;
+   begin
+      Read_Raw (S, Data'Address, Data'Size / SSU);
+      return Data;
+   end Read;
+
+   function Read (S : in out Mapped_Stream) return uint32 is
+      Data : uint32;
+   begin
+      Read_Raw (S, Data'Address, Data'Size / SSU);
+      return Data;
+   end Read;
+
+   function Read (S : in out Mapped_Stream) return uint64 is
+      Data : uint64;
+   begin
+      Read_Raw (S, Data'Address, Data'Size / SSU);
+      return Data;
+   end Read;
+
+   function Read (S : in out Mapped_Stream) return int8 is
+      Data : int8;
+   begin
+      Read_Raw (S, Data'Address, Data'Size / SSU);
+      return Data;
+   end Read;
+
+   function Read (S : in out Mapped_Stream) return int16 is
+      Data : int16;
+   begin
+      Read_Raw (S, Data'Address, Data'Size / SSU);
+      return Data;
+   end Read;
+
+   function Read (S : in out Mapped_Stream) return int32 is
+      Data : int32;
+   begin
+      Read_Raw (S, Data'Address, Data'Size / SSU);
+      return Data;
+   end Read;
+
+   function Read (S : in out Mapped_Stream) return int64 is
+      Data : int64;
+   begin
+      Read_Raw (S, Data'Address, Data'Size / SSU);
+      return Data;
+   end Read;
+
+   ------------------
+   -- Read_Address --
+   ------------------
+
+   function Read_Address
+     (Obj : Object_File; S : in out Mapped_Stream) return uint64 is
+      Address_32 : uint32;
+      Address_64 : uint64;
+
+   begin
+      case Obj.Arch is
+         when i386
+            | MIPS
+            | PPC
+            | SPARC
+         =>
+            Address_32 := Read (S);
+            return uint64 (Address_32);
+
+         when IA64
+            | PPC64
+            | SPARC64
+            | x86_64
+         =>
+            Address_64 := Read (S);
+            return Address_64;
+
+         when Unknown =>
+            raise Format_Error with "unrecognized machine architecture";
+      end case;
+   end Read_Address;
+
+   -------------------
+   -- Read_C_String --
+   -------------------
+
+   procedure Read_C_String (S : in out Mapped_Stream; B : out Buffer) is
+      J : Integer := 0;
+
+   begin
+      loop
+         --  Handle overflow case
+
+         if J = B'Last then
+            B (J) := 0;
+            exit;
+         end if;
+
+         B (J) := Read (S);
+         exit when B (J) = 0;
+         J := J + 1;
+      end loop;
+   end Read_C_String;
+
+   -------------------
+   -- Read_C_String --
+   -------------------
+
+   function Read_C_String (S : in out Mapped_Stream) return Str_Access is
+      Res : constant Str_Access := Read (S);
+
+   begin
+      for J in Res'Range loop
+         if S.Off + Offset (J - 1) > Offset (Last (S.Region)) then
+            raise IO_Error with "could not read from object file";
+         end if;
+
+         if Res (J) = ASCII.NUL then
+            S.Off := S.Off + Offset (J);
+            return Res;
+         end if;
+      end loop;
+
+      --  Overflow case
+      raise Constraint_Error;
+   end Read_C_String;
+
+   -----------------
+   -- Read_LEB128 --
+   -----------------
+
+   function Read_LEB128 (S : in out Mapped_Stream) return uint32 is
+      B     : uint8;
+      Shift : Integer := 0;
+      Res   : uint32 := 0;
+
+   begin
+      loop
+         B := Read (S);
+         Res := Res or Shift_Left (uint32 (B and 16#7f#), Shift);
+         exit when (B and 16#80#) = 0;
+         Shift := Shift + 7;
+      end loop;
+
+      return Res;
+   end Read_LEB128;
+
+   function Read_LEB128 (S : in out Mapped_Stream) return int32 is
+      B     : uint8;
+      Shift : Integer := 0;
+      Res   : uint32 := 0;
+
+   begin
+      loop
+         B := Read (S);
+         Res := Res or Shift_Left (uint32 (B and 16#7f#), Shift);
+         Shift := Shift + 7;
+         exit when (B and 16#80#) = 0;
+      end loop;
+
+      if Shift < 32 and then (Res and Shift_Left (1, Shift - 1)) /= 0 then
+         Res := Res or Shift_Left (-1, Shift);
+      end if;
+
+      return To_int32 (Res);
+   end Read_LEB128;
+
+   -----------------
+   -- Read_Symbol --
+   -----------------
+
+   function Read_Symbol
+     (Obj : in out Object_File;
+      Off : Offset) return Object_Symbol is
+   begin
+      case Obj.Format is
+         when ELF32      => return ELF32_Ops.Read_Symbol   (Obj, Off);
+         when ELF64      => return ELF64_Ops.Read_Symbol   (Obj, Off);
+         when Any_PECOFF => return PECOFF_Ops.Read_Symbol  (Obj, Off);
+         when XCOFF32    => return XCOFF32_Ops.Read_Symbol (Obj, Off);
+      end case;
+   end Read_Symbol;
+
+   ----------
+   -- Seek --
+   ----------
+
+   procedure Seek (S : in out Mapped_Stream; Off : Offset) is
+   begin
+      if Off < 0 or else Off > Offset (Last (S.Region)) then
+         raise IO_Error with "could not seek to offset in object file";
+      end if;
+
+      S.Off := Off;
+   end Seek;
+
+   ----------
+   -- Size --
+   ----------
+
+   function Size (Sec : Object_Section) return uint64 is
+   begin
+      return Sec.Size;
+   end Size;
+
+   function Size (Sym : Object_Symbol) return uint64 is
+   begin
+      return Sym.Size;
+   end Size;
+
+   ------------
+   -- Strlen --
+   ------------
+
+   function Strlen (Buf : Buffer) return int32 is
+   begin
+      return int32 (CRTL.strlen (Buf'Address));
+   end Strlen;
+
+   -----------
+   -- Spans --
+   -----------
+
+   function Spans (Sym : Object_Symbol; Addr : uint64) return Boolean is
+   begin
+      return Addr >= Sym.Value and then Addr < Sym.Value + Sym.Size;
+   end Spans;
+
+   ---------------
+   -- To_String --
+   ---------------
+
+   function To_String (Buf : Buffer) return String is
+      Result : String (1 .. Integer (CRTL.strlen (Buf'Address)));
+      for Result'Address use Buf'Address;
+      pragma Import (Ada, Result);
+
+   begin
+      return Result;
+   end To_String;
+
+   -----------------------
+   -- To_String_Ptr_Len --
+   -----------------------
+
+   function To_String_Ptr_Len
+     (Ptr : Mmap.Str_Access;
+      Max_Len : Natural := Natural'Last) return String_Ptr_Len is
+   begin
+      for I in 1 .. Max_Len loop
+         if Ptr (I) = ASCII.NUL then
+            return (Ptr, I - 1);
+         end if;
+      end loop;
+      return (Ptr, Max_Len);
+   end To_String_Ptr_Len;
+
+   ------------------------
+   -- Trim_Trailing_Nuls --
+   ------------------------
+
+   function Trim_Trailing_Nuls (Str : String) return String is
+   begin
+      for J in Str'Range loop
+         if Str (J) = ASCII.NUL then
+            return Str (Str'First .. J - 1);
+         end if;
+      end loop;
+
+      return Str;
+   end Trim_Trailing_Nuls;
+
+   -----------
+   -- Value --
+   -----------
+
+   function Value (Sym : Object_Symbol) return uint64 is
+   begin
+      return Sym.Value;
+   end Value;
+
+end System.Object_Reader;
diff --git a/gcc/ada/s-objrea.ads b/gcc/ada/s-objrea.ads
new file mode 100644 (file)
index 0000000..1d48536
--- /dev/null
@@ -0,0 +1,451 @@
+------------------------------------------------------------------------------
+--                                                                          --
+--                         GNAT COMPILER COMPONENTS                         --
+--                                                                          --
+--                 S Y S T E M . O B J E C T _ R E A D E R                  --
+--                                                                          --
+--                                 S p e c                                  --
+--                                                                          --
+--          Copyright (C) 2009-2017, 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 package implements a simple, minimal overhead reader for object files
+--  composed of sections of untyped heterogeneous binary data.
+
+with Interfaces;
+with System.Mmap;
+
+package System.Object_Reader is
+
+   --------------
+   --  Limits  --
+   --------------
+
+   BUFFER_SIZE : constant := 8 * 1024;
+
+   ------------------
+   -- Object files --
+   ------------------
+
+   type Object_File (<>) is private;
+
+   type Object_File_Access is access Object_File;
+
+   ---------------------
+   -- Object sections --
+   ----------------------
+
+   type Object_Section is private;
+
+   Null_Section : constant Object_Section;
+
+   --------------------
+   -- Object symbols --
+   --------------------
+
+   type Object_Symbol is private;
+
+   ------------------------
+   -- Object format type --
+   ------------------------
+
+   type Object_Format is
+     (ELF32,
+      --  Object format is 32-bit ELF
+
+      ELF64,
+      --  Object format is 64-bit ELF
+
+      PECOFF,
+      --  Object format is Microsoft PECOFF
+
+      PECOFF_PLUS,
+      --  Object format is Microsoft PECOFF+
+
+      XCOFF32);
+      --  Object format is AIX 32-bit XCOFF
+
+   --  PECOFF | PECOFF_PLUS appears so often as a case choice, would
+   --  seem a good idea to have a subtype name covering these two choices ???
+
+   ------------------------------
+   -- Object architecture type --
+   ------------------------------
+
+   type Object_Arch is
+     (Unknown,
+      --  The target architecture has not yet been determined
+
+      SPARC,
+      --  32-bit SPARC
+
+      SPARC64,
+      --  64-bit SPARC
+
+      i386,
+      --  Intel IA32
+
+      MIPS,
+      --  MIPS Technologies MIPS
+
+      x86_64,
+      --  x86-64 (64-bit AMD/Intel)
+
+      IA64,
+      --  Intel IA64
+
+      PPC,
+      --  32-bit PowerPC
+
+      PPC64);
+      --  64-bit PowerPC
+
+   ------------------
+   -- Target types --
+   ------------------
+
+   subtype Offset is Interfaces.Integer_64;
+
+   subtype uint8  is Interfaces.Unsigned_8;
+   subtype uint16 is Interfaces.Unsigned_16;
+   subtype uint32 is Interfaces.Unsigned_32;
+   subtype uint64 is Interfaces.Unsigned_64;
+
+   subtype int8  is Interfaces.Integer_8;
+   subtype int16 is Interfaces.Integer_16;
+   subtype int32 is Interfaces.Integer_32;
+   subtype int64 is Interfaces.Integer_64;
+
+   type Buffer is array (0 .. BUFFER_SIZE - 1) of uint8;
+
+   type String_Ptr_Len is record
+      Ptr : Mmap.Str_Access;
+      Len : Natural;
+   end record;
+   --  A string made from a pointer and a length. Not all strings for name
+   --  are C strings: COFF inlined symbol names have a max length of 8.
+
+   -------------------------------------------
+   -- Operations on buffers of untyped data --
+   -------------------------------------------
+
+   function To_String (Buf : Buffer) return String;
+   --  Construct string from C style null-terminated string stored in a buffer
+
+   function To_String_Ptr_Len
+     (Ptr : Mmap.Str_Access;
+      Max_Len : Natural := Natural'Last) return String_Ptr_Len;
+   --  Convert PTR to a String_Ptr_Len.
+
+   function Strlen (Buf : Buffer) return int32;
+   --  Return the length of a C style null-terminated string
+
+   -------------------------
+   -- Opening and closing --
+   -------------------------
+
+   function Open
+     (File_Name    : String;
+      In_Exception : Boolean := False) return Object_File_Access;
+   --  Open the object file and initialize the reader. In_Exception is true
+   --  when the parsing is done as part of an exception handler decorator. In
+   --  this mode we do not want to raise an exception.
+
+   procedure Close (Obj : in out Object_File);
+   --  Close the object file
+
+   -----------------------
+   -- Sequential access --
+   -----------------------
+
+   type Mapped_Stream is private;
+   --  Provide an abstraction of a stream on a memory mapped file
+
+   function Create_Stream (Mf : System.Mmap.Mapped_File;
+                           File_Offset : System.Mmap.File_Size;
+                           File_Length : System.Mmap.File_Size)
+                          return Mapped_Stream;
+   --  Create a stream from Mf
+
+   procedure Close (S : in out Mapped_Stream);
+   --  Close the stream (deallocate memory)
+
+   procedure Read_Raw
+     (S   : in out Mapped_Stream;
+      Addr  : Address;
+      Size  : uint32);
+   pragma Inline (Read_Raw);
+   --  Read a number of fixed sized records
+
+   procedure Seek (S : in out Mapped_Stream; Off : Offset);
+   --  Seek to an absolute offset in bytes
+
+   procedure Tell (Obj : in out Mapped_Stream; Off : out Offset)
+     with Inline;
+   function Tell (Obj : Mapped_Stream) return Offset
+     with Inline;
+   --  Fetch the current offset
+
+   function Length (Obj : Mapped_Stream) return Offset
+     with Inline;
+   --  Length of the stream
+
+   function Read (S : in out Mapped_Stream) return Mmap.Str_Access;
+   --  Provide a pointer in memory at the current offset
+
+   function Read (S : in out Mapped_Stream) return String_Ptr_Len;
+   --  Provide a pointer in memory at the current offset
+
+   function Read (S : in out Mapped_Stream) return uint8;
+   function Read (S : in out Mapped_Stream) return uint16;
+   function Read (S : in out Mapped_Stream) return uint32;
+   function Read (S : in out Mapped_Stream) return uint64;
+   function Read (S : in out Mapped_Stream) return int8;
+   function Read (S : in out Mapped_Stream) return int16;
+   function Read (S : in out Mapped_Stream) return int32;
+   function Read (S : in out Mapped_Stream) return int64;
+   --  Read a scalar
+
+   function Read_Address
+     (Obj : Object_File; S : in out Mapped_Stream) return uint64;
+   --  Read either a 64 or 32 bit address from the file stream depending on the
+   --  address size of the target architecture and promote it to a 64 bit type.
+
+   function Read_LEB128 (S : in out Mapped_Stream) return uint32;
+   function Read_LEB128 (S : in out Mapped_Stream) return int32;
+   --  Read a value encoding in Little-Endian Base 128 format
+
+   procedure Read_C_String (S : in out Mapped_Stream; B : out Buffer);
+   function Read_C_String (S : in out Mapped_Stream) return Mmap.Str_Access;
+   --  Read a C style NULL terminated string
+
+   function Offset_To_String
+     (S : in out Mapped_Stream;
+      Off : Offset) return String;
+   --  Construct a string from a C style NULL terminated string located at an
+   --  offset into the object file.
+
+   ------------------------
+   -- Object information --
+   ------------------------
+
+   function Arch (Obj : Object_File) return Object_Arch;
+   --  Return the object architecture
+
+   function Format (Obj : Object_File) return Object_Format;
+   --  Return the object file format
+
+   function Get_Load_Address (Obj : Object_File) return uint64;
+   --  Return the load address defined in Obj. May raise Format_Error if not
+   --  implemented
+
+   function Num_Sections (Obj : Object_File) return uint32;
+   --  Return the number of sections composing the object file
+
+   function Get_Section
+     (Obj   : in out Object_File;
+      Shnum : uint32) return Object_Section;
+   --  Return the Nth section (numbered from zero)
+
+   function Get_Section
+     (Obj      : in out Object_File;
+      Sec_Name : String) return Object_Section;
+   --  Return a section by name
+
+   function Create_Stream
+     (Obj : Object_File;
+      Sec : Object_Section) return Mapped_Stream;
+   --  Create a stream for section Sec
+
+   procedure Get_Memory_Bounds
+     (Obj   : in out Object_File;
+      Low, High : out uint64);
+   --  Return the low and high addresses of the code for the object file. Can
+   --  be used to check if an address in within this object file. This
+   --  procedure is not efficient and the result should be saved to avoid
+   --  recomputation.
+
+   -------------------------
+   -- Section information --
+   -------------------------
+
+   function Name
+     (Obj : in out Object_File;
+      Sec : Object_Section) return String;
+   --  Return the name of a section as a string
+
+   function Size (Sec : Object_Section) return uint64;
+   --  Return the size of a section in bytes
+
+   function Num (Sec : Object_Section) return uint32;
+   --  Return the index of a section from zero
+
+   function Off (Sec : Object_Section) return Offset;
+   --  Return the byte offset of the section within the object
+
+   ------------------------------
+   -- Symbol table information --
+   ------------------------------
+
+   Null_Symbol : constant Object_Symbol;
+   --  An empty symbol table entry.
+
+   function First_Symbol (Obj : in out Object_File) return Object_Symbol;
+   --  Return the first element in the symbol table or Null_Symbol if the
+   --  symbol table is empty.
+
+   function Next_Symbol
+     (Obj  : in out Object_File;
+      Prev : Object_Symbol) return Object_Symbol;
+   --  Return the element following Prev in the symbol table, or Null_Symbol if
+   --  Prev is the last symbol in the table.
+
+   function Read_Symbol
+     (Obj : in out Object_File;
+      Off : Offset) return Object_Symbol;
+   --  Read symbol at Off
+
+   function Name
+     (Obj : in out Object_File;
+      Sym : Object_Symbol) return String_Ptr_Len;
+   --  Return the name of the symbol
+
+   function Decoded_Ada_Name
+     (Obj : in out Object_File;
+      Sym : String_Ptr_Len) return String;
+   --  Return the decoded name of a symbol encoded as per exp_dbug.ads
+
+   function Strip_Leading_Char
+     (Obj : in out Object_File;
+      Sym : String_Ptr_Len) return Positive;
+   --  Return the index of the first character to decode the name. This can
+   --  strip one character for ABI with a prefix (like x86 for PECOFF).
+
+   function Value (Sym : Object_Symbol) return uint64;
+   --  Return the name of the symbol
+
+   function Size (Sym : Object_Symbol) return uint64;
+   --  Return the size of the symbol in bytes
+
+   function Spans (Sym : Object_Symbol; Addr : uint64) return Boolean;
+   --  Determine whether a particular address corresponds to the range
+   --  referenced by this symbol.
+
+   function Off (Sym : Object_Symbol) return Offset;
+   --  Return the offset of the symbol.
+
+   ----------------
+   -- Exceptions --
+   ----------------
+
+   IO_Error : exception;
+   --  Input/Output error reading file
+
+   Format_Error : exception;
+   --  Encountered a problem parsing the object
+
+private
+   type Mapped_Stream is record
+      Region : System.Mmap.Mapped_Region;
+      Off    : Offset;
+      Len    : Offset;
+   end record;
+
+   subtype ELF is Object_Format range ELF32 .. ELF64;
+   subtype Any_PECOFF is Object_Format range PECOFF .. PECOFF_PLUS;
+
+   type Object_File (Format : Object_Format) is record
+      Mf           : System.Mmap.Mapped_File :=
+                        System.Mmap.Invalid_Mapped_File;
+      Arch         : Object_Arch := Unknown;
+
+      Num_Sections : uint32 := 0;
+      --  Number of sections
+
+      Symtab_Last : Offset;       --  Last offset of symbol table
+
+      In_Exception : Boolean := False;
+      --  True if the parsing is done as part of an exception handler
+
+      Sectab_Stream : Mapped_Stream;
+      --  Section table
+
+      Symtab_Stream : Mapped_Stream;
+      --  Symbol table
+
+      Symstr_Stream : Mapped_Stream;
+      --  Symbol strings
+
+      case Format is
+         when ELF =>
+            Secstr_Stream : Mapped_Stream;
+            --  Section strings
+         when Any_PECOFF =>
+            ImageBase   : uint64;       --  ImageBase value from header
+
+            --  Cache for latest result of Get_Section_Virtual_Address
+
+            GSVA_Sec  : uint32 := uint32'Last;
+            GSVA_Addr : uint64;
+         when XCOFF32 =>
+            null;
+      end case;
+   end record;
+
+   subtype ELF_Object_File is Object_File; -- with
+   --  Predicate => ELF_Object_File.Format in ELF;
+   subtype PECOFF_Object_File is Object_File; -- with
+   --  Predicate => PECOFF_Object_File.Format in Any_PECOFF;
+   subtype XCOFF32_Object_File is Object_File; -- with
+   --  Predicate => XCOFF32_Object_File.Format in XCOFF32;
+   --  ???Above predicates cause the compiler to crash when instantiating
+   --  ELF64_Ops (see package body).
+
+   type Object_Section is record
+      Num        : uint32 := 0;
+      --  Section index in the section table
+
+      Off        : Offset := 0;
+      --  First byte of the section in the object file
+
+      Addr       : uint64 := 0;
+      --  Load address of the section. Valid only when Flag_Alloc is true.
+
+      Size       : uint64 := 0;
+      --  Length of the section in bytes
+
+      Flag_Alloc : Boolean := False;
+      --  True if the section is mapped in memory by the OS loader
+   end record;
+
+   Null_Section : constant Object_Section := (0, 0, 0, 0, False);
+
+   type Object_Symbol is record
+      Off   : Offset := 0;  --  Offset of underlying symbol on disk
+      Next  : Offset := 0;  --  Offset of the following symbol
+      Value : uint64 := 0;  --  Value associated with this symbol
+      Size  : uint64 := 0;  --  Size of the referenced entity
+   end record;
+
+   Null_Symbol : constant Object_Symbol := (0, 0, 0, 0);
+end System.Object_Reader;
diff --git a/gcc/ada/s-trasym-dwarf.adb b/gcc/ada/s-trasym-dwarf.adb
new file mode 100644 (file)
index 0000000..9655722
--- /dev/null
@@ -0,0 +1,689 @@
+------------------------------------------------------------------------------
+--                                                                          --
+--                         GNAT RUN-TIME COMPONENTS                         --
+--                                                                          --
+--           S Y S T E M . T R A C E B A C K . S Y M B O L I C              --
+--                                                                          --
+--                                 B o d y                                  --
+--                                                                          --
+--                     Copyright (C) 1999-2017, AdaCore                     --
+--                                                                          --
+-- 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.      --
+--                                                                          --
+------------------------------------------------------------------------------
+
+--  Run-time symbolic traceback support for targets using DWARF debug data
+
+pragma Polling (Off);
+--  We must turn polling off for this unit, because otherwise we can get
+--  elaboration circularities when polling is turned on.
+
+with Ada.Unchecked_Deallocation;
+
+with Ada.Exceptions.Traceback; use Ada.Exceptions.Traceback;
+with Ada.Containers.Generic_Array_Sort;
+
+with System.Address_To_Access_Conversions;
+with System.Soft_Links;
+with System.CRTL;
+with System.Dwarf_Lines;
+with System.Exception_Traces;
+with System.Standard_Library;
+with System.Traceback_Entries;
+with System.Strings;
+with System.Bounded_Strings;
+
+package body System.Traceback.Symbolic is
+
+   use System.Bounded_Strings;
+   use System.Dwarf_Lines;
+
+   subtype Big_String is String (Positive);
+   --  To deal with C strings
+
+   package Big_String_Conv is new System.Address_To_Access_Conversions
+     (Big_String);
+
+   type Module_Cache;
+   type Module_Cache_Acc is access all Module_Cache;
+
+   type Module_Cache is record
+      Name : Strings.String_Access;
+      --  Name of the module
+
+      C : Dwarf_Context (In_Exception => True);
+      --  Context to symbolize an address within this module
+
+      Chain : Module_Cache_Acc;
+   end record;
+
+   procedure Free is new Ada.Unchecked_Deallocation
+     (Module_Cache,
+      Module_Cache_Acc);
+
+   Cache_Chain : Module_Cache_Acc;
+   --  Simply linked list of modules
+
+   type Module_Array is array (Natural range <>) of Module_Cache_Acc;
+   type Module_Array_Acc is access Module_Array;
+
+   Modules_Cache : Module_Array_Acc;
+   --  Sorted array of cached modules (if not null)
+
+   Exec_Module : aliased Module_Cache;
+   --  Context for the executable
+
+   type Init_State is (Uninitialized, Initialized, Failed);
+   Exec_Module_State : Init_State := Uninitialized;
+   --  How Exec_Module is initialized
+
+   procedure Init_Exec_Module;
+   --  Initialize Exec_Module if not already initialized
+
+   function Symbolic_Traceback
+     (Traceback    : System.Traceback_Entries.Tracebacks_Array;
+      Suppress_Hex : Boolean) return String;
+   function Symbolic_Traceback
+     (E            : Ada.Exceptions.Exception_Occurrence;
+      Suppress_Hex : Boolean) return String;
+   --  Suppress_Hex means do not print any hexadecimal addresses, even if the
+   --  symbol is not available.
+
+   function Lt (Left, Right : Module_Cache_Acc) return Boolean;
+   --  Sort function for Module_Cache
+
+   procedure Init_Module
+     (Module       : out Module_Cache;
+      Success      : out Boolean;
+      Module_Name  :     String;
+      Load_Address :     Address := Null_Address);
+   --  Initialize Module
+
+   procedure Close_Module (Module : in out Module_Cache);
+   --  Finalize Module
+
+   function Value (Item : System.Address) return String;
+   --  Return the String contained in Item, up until the first NUL character
+
+   pragma Warnings (Off, "*Add_Module_To_Cache*");
+   procedure Add_Module_To_Cache (Module_Name : String);
+   --  To be called by Build_Cache_For_All_Modules to add a new module to the
+   --  list. May not be referenced.
+
+   package Module_Name is
+
+      procedure Build_Cache_For_All_Modules;
+      --  Create the cache for all current modules
+
+      function Get (Addr : access System.Address) return String;
+      --  Returns the module name for the given address, Addr may be updated
+      --  to be set relative to a shared library. This depends on the platform.
+      --  Returns an empty string for the main executable.
+
+      function Is_Supported return Boolean;
+      pragma Inline (Is_Supported);
+      --  Returns True if Module_Name is supported, so if the traceback is
+      --  supported for shared libraries.
+
+   end Module_Name;
+
+   package body Module_Name is separate;
+
+   function Executable_Name return String;
+   --  Returns the executable name as reported by argv[0]. If gnat_argv not
+   --  initialized or if argv[0] executable not found in path, function returns
+   --  an empty string.
+
+   function Get_Executable_Load_Address return System.Address;
+   pragma Import
+     (C,
+      Get_Executable_Load_Address,
+      "__gnat_get_executable_load_address");
+   --  Get the load address of the executable, or Null_Address if not known
+
+   procedure Hexa_Traceback
+     (Traceback    :        Tracebacks_Array;
+      Suppress_Hex :        Boolean;
+      Res          : in out Bounded_String);
+   --  Non-symbolic traceback (simply write addresses in hexa)
+
+   procedure Symbolic_Traceback_No_Lock
+     (Traceback    :        Tracebacks_Array;
+      Suppress_Hex :        Boolean;
+      Res          : in out Bounded_String);
+   --  Like the public Symbolic_Traceback_No_Lock except there is no provision
+   --  against concurrent accesses.
+
+   procedure Module_Symbolic_Traceback
+     (Traceback    :        Tracebacks_Array;
+      Module       :        Module_Cache;
+      Suppress_Hex :        Boolean;
+      Res          : in out Bounded_String);
+   --  Returns the Traceback for a given module
+
+   procedure Multi_Module_Symbolic_Traceback
+     (Traceback    :        Tracebacks_Array;
+      Suppress_Hex :        Boolean;
+      Res          : in out Bounded_String);
+   --  Build string containing symbolic traceback for the given call chain
+
+   procedure Multi_Module_Symbolic_Traceback
+     (Traceback    :        Tracebacks_Array;
+      Module       :        Module_Cache;
+      Suppress_Hex :        Boolean;
+      Res          : in out Bounded_String);
+   --  Likewise but using Module
+
+   Max_String_Length : constant := 4096;
+   --  Arbitrary limit on Bounded_Str length
+
+   -----------
+   -- Value --
+   -----------
+
+   function Value (Item : System.Address) return String is
+   begin
+      if Item /= Null_Address then
+         for J in Big_String'Range loop
+            if Big_String_Conv.To_Pointer (Item) (J) = ASCII.NUL then
+               return Big_String_Conv.To_Pointer (Item) (1 .. J - 1);
+            end if;
+         end loop;
+      end if;
+
+      return "";
+   end Value;
+
+   -------------------------
+   -- Add_Module_To_Cache --
+   -------------------------
+
+   procedure Add_Module_To_Cache (Module_Name : String) is
+      Module  : Module_Cache_Acc;
+      Success : Boolean;
+   begin
+      Module := new Module_Cache;
+      Init_Module (Module.all, Success, Module_Name);
+      if not Success then
+         Free (Module);
+         return;
+      end if;
+      Module.Chain := Cache_Chain;
+      Cache_Chain  := Module;
+   end Add_Module_To_Cache;
+
+   ----------------------
+   -- Init_Exec_Module --
+   ----------------------
+
+   procedure Init_Exec_Module is
+   begin
+      if Exec_Module_State = Uninitialized then
+         declare
+            Exec_Path : constant String  := Executable_Name;
+            Exec_Load : constant Address := Get_Executable_Load_Address;
+            Success   : Boolean;
+         begin
+            Init_Module (Exec_Module, Success, Exec_Path, Exec_Load);
+
+            if Success then
+               Exec_Module_State := Initialized;
+            else
+               Exec_Module_State := Failed;
+            end if;
+         end;
+      end if;
+   end Init_Exec_Module;
+
+   --------
+   -- Lt --
+   --------
+
+   function Lt (Left, Right : Module_Cache_Acc) return Boolean is
+   begin
+      return Low (Left.C) < Low (Right.C);
+   end Lt;
+
+   -----------------------------
+   -- Module_Cache_Array_Sort --
+   -----------------------------
+
+   procedure Module_Cache_Array_Sort is new Ada.Containers.Generic_Array_Sort
+     (Natural,
+      Module_Cache_Acc,
+      Module_Array,
+      Lt);
+
+   ------------------
+   -- Enable_Cache --
+   ------------------
+
+   procedure Enable_Cache (Include_Modules : Boolean := False) is
+   begin
+      --  Can be called at most once
+      if Cache_Chain /= null then
+         return;
+      end if;
+
+      --  Add all modules
+      Init_Exec_Module;
+      Cache_Chain := Exec_Module'Access;
+
+      if Include_Modules then
+         Module_Name.Build_Cache_For_All_Modules;
+      end if;
+
+      --  Build and fill the array of modules
+      declare
+         Count  : Natural;
+         Module : Module_Cache_Acc;
+      begin
+         for Phase in 1 .. 2 loop
+            Count  := 0;
+            Module := Cache_Chain;
+            while Module /= null loop
+               Count := Count + 1;
+
+               if Phase = 1 then
+                  Enable_Cache (Module.C);
+               else
+                  Modules_Cache (Count) := Module;
+               end if;
+               Module := Module.Chain;
+            end loop;
+
+            if Phase = 1 then
+               Modules_Cache := new Module_Array (1 .. Count);
+            end if;
+         end loop;
+      end;
+
+      --  Sort the array
+      Module_Cache_Array_Sort (Modules_Cache.all);
+   end Enable_Cache;
+
+   ---------------------
+   -- Executable_Name --
+   ---------------------
+
+   function Executable_Name return String is
+      --  We have to import gnat_argv as an Address to match the type of
+      --  gnat_argv in the binder generated file. Otherwise, we get spurious
+      --  warnings about type mismatch when LTO is turned on.
+
+      Gnat_Argv : System.Address;
+      pragma Import (C, Gnat_Argv, "gnat_argv");
+
+      type Argv_Array is array (0 .. 0) of System.Address;
+      package Conv is new System.Address_To_Access_Conversions (Argv_Array);
+
+      function locate_exec_on_path (A : System.Address) return System.Address;
+      pragma Import (C, locate_exec_on_path, "__gnat_locate_exec_on_path");
+
+   begin
+      if Gnat_Argv = Null_Address then
+         return "";
+      end if;
+
+      declare
+         Addr : constant System.Address :=
+           locate_exec_on_path (Conv.To_Pointer (Gnat_Argv) (0));
+         Result : constant String := Value (Addr);
+
+      begin
+         --  The buffer returned by locate_exec_on_path was allocated using
+         --  malloc, so we should use free to release the memory.
+
+         if Addr /= Null_Address then
+            System.CRTL.free (Addr);
+         end if;
+
+         return Result;
+      end;
+   end Executable_Name;
+
+   ------------------
+   -- Close_Module --
+   ------------------
+
+   procedure Close_Module (Module : in out Module_Cache) is
+   begin
+      Close (Module.C);
+      Strings.Free (Module.Name);
+   end Close_Module;
+
+   -----------------
+   -- Init_Module --
+   -----------------
+
+   procedure Init_Module
+     (Module       : out Module_Cache;
+      Success      : out Boolean;
+      Module_Name  :     String;
+      Load_Address :     Address := Null_Address)
+   is
+   begin
+      --  Early return if the module is not known
+
+      if Module_Name = "" then
+         Success := False;
+         return;
+      end if;
+
+      Open (Module_Name, Module.C, Success);
+
+      --  If a module can't be opened just return now, we just cannot give more
+      --  information in this case.
+
+      if not Success then
+         return;
+      end if;
+
+      Set_Load_Address (Module.C, Load_Address);
+
+      Module.Name := new String'(Module_Name);
+   end Init_Module;
+
+   -------------------------------
+   -- Module_Symbolic_Traceback --
+   -------------------------------
+
+   procedure Module_Symbolic_Traceback
+     (Traceback    :        Tracebacks_Array;
+      Module       :        Module_Cache;
+      Suppress_Hex :        Boolean;
+      Res          : in out Bounded_String)
+   is
+      Success : Boolean := False;
+   begin
+      if Symbolic.Module_Name.Is_Supported then
+         Append (Res, '[');
+         Append (Res, Module.Name.all);
+         Append (Res, ']' & ASCII.LF);
+      end if;
+
+      Dwarf_Lines.Symbolic_Traceback
+        (Module.C,
+         Traceback,
+         Suppress_Hex,
+         Success,
+         Res);
+
+      if not Success then
+         Hexa_Traceback (Traceback, Suppress_Hex, Res);
+      end if;
+
+      --  We must not allow an unhandled exception here, since this function
+      --  may be installed as a decorator for all automatic exceptions.
+
+   exception
+      when others =>
+         return;
+   end Module_Symbolic_Traceback;
+
+   -------------------------------------
+   -- Multi_Module_Symbolic_Traceback --
+   -------------------------------------
+
+   procedure Multi_Module_Symbolic_Traceback
+     (Traceback    :        Tracebacks_Array;
+      Suppress_Hex :        Boolean;
+      Res          : in out Bounded_String)
+   is
+      F : constant Natural := Traceback'First;
+   begin
+      if Traceback'Length = 0 or else Is_Full (Res) then
+         return;
+      end if;
+
+      if Modules_Cache /= null then
+         --  Search in the cache
+
+         declare
+            Addr        : constant Address := Traceback (F);
+            Hi, Lo, Mid : Natural;
+         begin
+            Lo := Modules_Cache'First;
+            Hi := Modules_Cache'Last;
+            while Lo <= Hi loop
+               Mid := (Lo + Hi) / 2;
+               if Addr < Low (Modules_Cache (Mid).C) then
+                  Hi := Mid - 1;
+               elsif Is_Inside (Modules_Cache (Mid).C, Addr) then
+                  Multi_Module_Symbolic_Traceback
+                    (Traceback,
+                     Modules_Cache (Mid).all,
+                     Suppress_Hex,
+                     Res);
+                  return;
+               else
+                  Lo := Mid + 1;
+               end if;
+            end loop;
+
+            --  Not found
+            Hexa_Traceback (Traceback (F .. F), Suppress_Hex, Res);
+            Multi_Module_Symbolic_Traceback
+              (Traceback (F + 1 .. Traceback'Last),
+               Suppress_Hex,
+               Res);
+         end;
+      else
+
+         --  First try the executable
+         if Is_Inside (Exec_Module.C, Traceback (F)) then
+            Multi_Module_Symbolic_Traceback
+              (Traceback,
+               Exec_Module,
+               Suppress_Hex,
+               Res);
+            return;
+         end if;
+
+         --  Otherwise, try a shared library
+         declare
+            Addr    : aliased System.Address := Traceback (F);
+            M_Name  : constant String        := Module_Name.Get (Addr'Access);
+            Module  : Module_Cache;
+            Success : Boolean;
+         begin
+            Init_Module (Module, Success, M_Name, System.Null_Address);
+            if Success then
+               Multi_Module_Symbolic_Traceback
+                 (Traceback,
+                  Module,
+                  Suppress_Hex,
+                  Res);
+               Close_Module (Module);
+            else
+               --  Module not found
+               Hexa_Traceback (Traceback (F .. F), Suppress_Hex, Res);
+               Multi_Module_Symbolic_Traceback
+                 (Traceback (F + 1 .. Traceback'Last),
+                  Suppress_Hex,
+                  Res);
+            end if;
+         end;
+      end if;
+   end Multi_Module_Symbolic_Traceback;
+
+   procedure Multi_Module_Symbolic_Traceback
+     (Traceback    :        Tracebacks_Array;
+      Module       :        Module_Cache;
+      Suppress_Hex :        Boolean;
+      Res          : in out Bounded_String)
+   is
+      Pos : Positive;
+   begin
+      --  Will symbolize the first address...
+
+      Pos := Traceback'First + 1;
+
+      --  ... and all addresses in the same module
+
+      Same_Module :
+      loop
+         exit Same_Module when Pos > Traceback'Last;
+
+         --  Get address to check for corresponding module name
+
+         exit Same_Module when not Is_Inside (Module.C, Traceback (Pos));
+
+         Pos := Pos + 1;
+      end loop Same_Module;
+
+      Module_Symbolic_Traceback
+        (Traceback (Traceback'First .. Pos - 1),
+         Module,
+         Suppress_Hex,
+         Res);
+      Multi_Module_Symbolic_Traceback
+        (Traceback (Pos .. Traceback'Last),
+         Suppress_Hex,
+         Res);
+   end Multi_Module_Symbolic_Traceback;
+
+   --------------------
+   -- Hexa_Traceback --
+   --------------------
+
+   procedure Hexa_Traceback
+     (Traceback    :        Tracebacks_Array;
+      Suppress_Hex :        Boolean;
+      Res          : in out Bounded_String)
+   is
+      use System.Traceback_Entries;
+   begin
+      if Suppress_Hex then
+         Append (Res, "...");
+         Append (Res, ASCII.LF);
+      else
+         for J in Traceback'Range loop
+            Append_Address (Res, PC_For (Traceback (J)));
+            Append (Res, ASCII.LF);
+         end loop;
+      end if;
+   end Hexa_Traceback;
+
+   --------------------------------
+   -- Symbolic_Traceback_No_Lock --
+   --------------------------------
+
+   procedure Symbolic_Traceback_No_Lock
+     (Traceback    :        Tracebacks_Array;
+      Suppress_Hex :        Boolean;
+      Res          : in out Bounded_String)
+   is
+   begin
+      if Symbolic.Module_Name.Is_Supported then
+         Multi_Module_Symbolic_Traceback (Traceback, Suppress_Hex, Res);
+      else
+         if Exec_Module_State = Failed then
+            Append (Res, "Call stack traceback locations:" & ASCII.LF);
+            Hexa_Traceback (Traceback, Suppress_Hex, Res);
+         else
+            Module_Symbolic_Traceback
+              (Traceback,
+               Exec_Module,
+               Suppress_Hex,
+               Res);
+         end if;
+      end if;
+   end Symbolic_Traceback_No_Lock;
+
+   ------------------------
+   -- Symbolic_Traceback --
+   ------------------------
+
+   function Symbolic_Traceback
+     (Traceback    : Tracebacks_Array;
+      Suppress_Hex : Boolean) return String
+   is
+      Res : Bounded_String (Max_Length => Max_String_Length);
+   begin
+      System.Soft_Links.Lock_Task.all;
+      Init_Exec_Module;
+      Symbolic_Traceback_No_Lock (Traceback, Suppress_Hex, Res);
+      System.Soft_Links.Unlock_Task.all;
+
+      return To_String (Res);
+
+   exception
+      when others =>
+         System.Soft_Links.Unlock_Task.all;
+         raise;
+   end Symbolic_Traceback;
+
+   function Symbolic_Traceback
+     (Traceback : System.Traceback_Entries.Tracebacks_Array) return String is
+   begin
+      return Symbolic_Traceback (Traceback, Suppress_Hex => False);
+   end Symbolic_Traceback;
+
+   function Symbolic_Traceback_No_Hex
+     (Traceback : System.Traceback_Entries.Tracebacks_Array) return String is
+   begin
+      return Symbolic_Traceback (Traceback, Suppress_Hex => True);
+   end Symbolic_Traceback_No_Hex;
+
+   function Symbolic_Traceback
+     (E            : Ada.Exceptions.Exception_Occurrence;
+      Suppress_Hex : Boolean) return String
+   is
+   begin
+      return Symbolic_Traceback
+          (Ada.Exceptions.Traceback.Tracebacks (E),
+           Suppress_Hex);
+   end Symbolic_Traceback;
+
+   function Symbolic_Traceback
+     (E : Ada.Exceptions.Exception_Occurrence) return String
+   is
+   begin
+      return Symbolic_Traceback (E, Suppress_Hex => False);
+   end Symbolic_Traceback;
+
+   function Symbolic_Traceback_No_Hex
+     (E : Ada.Exceptions.Exception_Occurrence) return String is
+   begin
+      return Symbolic_Traceback (E, Suppress_Hex => True);
+   end Symbolic_Traceback_No_Hex;
+
+   Exception_Tracebacks_Symbolic : Integer;
+   pragma Import
+     (C,
+      Exception_Tracebacks_Symbolic,
+      "__gl_exception_tracebacks_symbolic");
+   --  Boolean indicating whether symbolic tracebacks should be generated.
+
+   use Standard_Library;
+begin
+   --  If this version of this package is available, and the binder switch -Es
+   --  was given, then we want to use this as the decorator by default, and we
+   --  want to turn on tracing for Unhandled_Raise_In_Main. Note that the user
+   --  cannot have already set Exception_Trace, because the runtime library is
+   --  elaborated before user-defined code.
+
+   if Exception_Tracebacks_Symbolic /= 0 then
+      Exception_Traces.Set_Trace_Decorator (Symbolic_Traceback'Access);
+      pragma Assert (Exception_Trace = RM_Convention);
+      Exception_Trace := Unhandled_Raise_In_Main;
+   end if;
+end System.Traceback.Symbolic;
diff --git a/gcc/ada/s-tsmona-linux.adb b/gcc/ada/s-tsmona-linux.adb
new file mode 100644 (file)
index 0000000..8c1f8b4
--- /dev/null
@@ -0,0 +1,190 @@
+------------------------------------------------------------------------------
+--                                                                          --
+--                         GNAT RUN-TIME COMPONENTS                         --
+--                                                                          --
+--  G N A T . T R A C E B A C K . S Y M B O L I C . M O D U L E _ N A M E   --
+--                                                                          --
+--                                 B o d y                                  --
+--                                                                          --
+--                     Copyright (C) 2012-2017, AdaCore                     --
+--                                                                          --
+-- 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 the GNU/Linux specific version of this package
+with Interfaces.C;              use Interfaces.C;
+
+with System.Address_Operations; use System.Address_Operations;
+
+separate (System.Traceback.Symbolic)
+
+package body Module_Name is
+
+   use System;
+
+   pragma Linker_Options ("-ldl");
+
+   function Is_Shared_Lib (Base : Address) return Boolean;
+   --  Returns True if a shared library
+
+   --  The principle is:
+
+   --  1. We get information about the module containing the address.
+
+   --  2. We check that the full pathname is pointing to a shared library.
+
+   --  3. for shared libraries, we return the non relocated address (so
+   --     the absolute address in the shared library).
+
+   --  4. we also return the full pathname of the module containing this
+   --     address.
+
+   -------------------
+   -- Is_Shared_Lib --
+   -------------------
+
+   function Is_Shared_Lib (Base : Address) return Boolean is
+      EI_NIDENT : constant := 16;
+      type u16 is mod 2 ** 16;
+
+      --  Just declare the needed header information, we just need to read the
+      --  type encoded in the second field.
+
+      type Elf32_Ehdr is record
+         e_ident : char_array (1 .. EI_NIDENT);
+         e_type  : u16;
+      end record;
+
+      ET_DYN : constant := 3; -- A shared lib if e_type = ET_DYN
+
+      Header : Elf32_Ehdr;
+      pragma Import (Ada, Header);
+      --  Suppress initialization in Normalized_Scalars mode
+      for Header'Address use Base;
+
+   begin
+      return Header.e_type = ET_DYN;
+   exception
+      when others =>
+         return False;
+   end Is_Shared_Lib;
+
+   ---------------------------------
+   -- Build_Cache_For_All_Modules --
+   ---------------------------------
+
+   procedure Build_Cache_For_All_Modules is
+      type link_map;
+      type link_map_acc is access all link_map;
+      pragma Convention (C, link_map_acc);
+
+      type link_map is record
+         l_addr : Address;
+         --  Base address of the shared object
+
+         l_name : Address;
+         --  Null-terminated absolute file name
+
+         l_ld   : Address;
+         --  Dynamic section
+
+         l_next, l_prev : link_map_acc;
+         --  Chain
+      end record;
+      pragma Convention (C, link_map);
+
+      type r_debug_type is record
+         r_version : Integer;
+         r_map : link_map_acc;
+      end record;
+      pragma Convention (C, r_debug_type);
+
+      r_debug : r_debug_type;
+      pragma Import (C, r_debug, "_r_debug");
+
+      lm : link_map_acc;
+   begin
+      lm := r_debug.r_map;
+      while lm /= null loop
+         if Big_String_Conv.To_Pointer (lm.l_name) (1) /= ASCII.NUL then
+            --  Discard non-file (like the executable itself or the gate).
+            Add_Module_To_Cache (Value (lm.l_name));
+         end if;
+         lm := lm.l_next;
+      end loop;
+   end Build_Cache_For_All_Modules;
+
+   ---------
+   -- Get --
+   ---------
+
+   function Get (Addr : access System.Address) return String is
+
+      --  Dl_info record for Linux, used to get sym reloc offset
+
+      type Dl_info is record
+         dli_fname : System.Address;
+         dli_fbase : System.Address;
+         dli_sname : System.Address;
+         dli_saddr : System.Address;
+      end record;
+
+      function dladdr
+        (addr : System.Address;
+         info : not null access Dl_info) return int;
+      pragma Import (C, dladdr, "dladdr");
+      --  This is a Linux extension and not POSIX
+
+      info : aliased Dl_info;
+
+   begin
+      if dladdr (Addr.all, info'Access) /= 0 then
+
+         --  If we have a shared library we need to adjust the address to
+         --  be relative to the base address of the library.
+
+         if Is_Shared_Lib (info.dli_fbase) then
+            Addr.all := SubA (Addr.all, info.dli_fbase);
+         end if;
+
+         return Value (info.dli_fname);
+
+      --  Not found, fallback to executable name
+
+      else
+         return "";
+      end if;
+
+   exception
+      when others =>
+         return "";
+   end Get;
+
+   ------------------
+   -- Is_Supported --
+   ------------------
+
+   function Is_Supported return Boolean is
+   begin
+      return True;
+   end Is_Supported;
+
+end Module_Name;
diff --git a/gcc/ada/s-tsmona-mingw.adb b/gcc/ada/s-tsmona-mingw.adb
new file mode 100644 (file)
index 0000000..46c35cd
--- /dev/null
@@ -0,0 +1,93 @@
+------------------------------------------------------------------------------
+--                                                                          --
+--                         GNAT RUN-TIME COMPONENTS                         --
+--                                                                          --
+--  G N A T . T R A C E B A C K . S Y M B O L I C . M O D U L E _ N A M E   --
+--                                                                          --
+--                                 B o d y                                  --
+--                                                                          --
+--                     Copyright (C) 2012-2017, AdaCore                     --
+--                                                                          --
+-- 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 the Windows specific version of this package
+
+with System.Win32; use System.Win32;
+
+separate (System.Traceback.Symbolic)
+
+package body Module_Name is
+
+   use System;
+
+   ---------------------------------
+   -- Build_Cache_For_All_Modules --
+   ---------------------------------
+
+   procedure Build_Cache_For_All_Modules is
+   begin
+      null;
+   end Build_Cache_For_All_Modules;
+
+   ---------
+   -- Get --
+   ---------
+
+   function Get (Addr : access System.Address) return String is
+      Res     : DWORD;
+      hModule : aliased HANDLE;
+      Path    : String (1 .. 1_024);
+
+   begin
+      if GetModuleHandleEx
+           (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+            Addr.all,
+            hModule'Access) = Win32.TRUE
+      then
+         Res := GetModuleFileName (hModule, Path'Address, Path'Length);
+
+         if FreeLibrary (hModule) = Win32.FALSE then
+            null;
+         end if;
+
+         if Res > 0 then
+            return Path (1 .. Positive (Res));
+         end if;
+      end if;
+
+      return "";
+
+   exception
+      when others =>
+         return "";
+   end Get;
+
+   ------------------
+   -- Is_Supported --
+   ------------------
+
+   function Is_Supported return Boolean is
+   begin
+      return True;
+   end Is_Supported;
+
+end Module_Name;