public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-2248] [Ada] Add DWARF 5 support to System.Dwarf_Line
@ 2021-07-12 12:51 Pierre-Marie de Rodat
  0 siblings, 0 replies; only message in thread
From: Pierre-Marie de Rodat @ 2021-07-12 12:51 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:5cb3843bca9a28c28dbc1fafd88c144a43e141df

commit r12-2248-g5cb3843bca9a28c28dbc1fafd88c144a43e141df
Author: Eric Botcazou <ebotcazou@adacore.com>
Date:   Fri Jun 18 16:47:48 2021 +0200

    [Ada] Add DWARF 5 support to System.Dwarf_Line
    
    gcc/ada/
    
            * libgnat/s-dwalin.ads: Adjust a few comments left and right.
            (Line_Info_Register): Comment out unused components.
            (Line_Info_Header): Add DWARF 5 support.
            (Dwarf_Context): Likewise.  Rename "prologue" into "header".
            * libgnat/s-dwalin.adb: Alphabetize "with" clauses.
            (DWARF constants): Add DWARF 5 support and reorder.
            (For_Each_Row): Adjust.
            (Initialize_Pass): Likewise.
            (Initialize_State_Machine): Likewise and fix typo.
            (Open): Add DWARF 5 support.
            (Parse_Prologue): Rename into...
            (Parse_Header): ...this and add DWARF 5 support.
            (Read_And_Execute_Isn): Rename into...
            (Read_And_Execute_Insn): ...this and adjust.
            (To_File_Name): Change parameter name and add DWARF 5 support.
            (Read_Entry_Format_Array): New procedure.
            (Skip_Form): Add DWARF 5 support and reorder.
            (Seek_Abbrev): Do not count entries and add DWARF 5 support.
            (Debug_Info_Lookup): Add DWARF 5 support.
            (Symbolic_Address.Set_Result): Likewise.
            (Symbolic_Address): Adjust.

Diff:
---
 gcc/ada/libgnat/s-dwalin.adb | 842 ++++++++++++++++++++++++++++++-------------
 gcc/ada/libgnat/s-dwalin.ads | 124 ++++---
 2 files changed, 653 insertions(+), 313 deletions(-)

diff --git a/gcc/ada/libgnat/s-dwalin.adb b/gcc/ada/libgnat/s-dwalin.adb
index 55989c53bd0..4a9d538c0e4 100644
--- a/gcc/ada/libgnat/s-dwalin.adb
+++ b/gcc/ada/libgnat/s-dwalin.adb
@@ -30,20 +30,20 @@
 ------------------------------------------------------------------------------
 
 with Ada.Characters.Handling;
+with Ada.Containers.Generic_Array_Sort;
 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.Bounded_Strings;   use System.Bounded_Strings;
 with System.IO;                use System.IO;
+with System.Mmap;              use System.Mmap;
 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;
+with System.Storage_Elements;  use System.Storage_Elements;
 
 package body System.Dwarf_Lines is
 
@@ -60,13 +60,19 @@ package body System.Dwarf_Lines is
      (S    : in out Mapped_Stream;
       Len  :    out Offset;
       Is64 :    out Boolean);
-   --  Read initial length as specified by Dwarf-4 7.2.2
+   --  Read initial length as specified by 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
+   --  Read a section offset, as specified by 7.4
+
+   procedure Read_Entry_Format_Array
+     (S    : in out Mapped_Stream;
+      A    :    out Entry_Format_Array;
+      Len  :        uint8);
+   --  Read an entry format array, as specified by 6.2.4.1
 
    procedure Read_Aranges_Entry
      (C     : in out Dwarf_Context;
@@ -111,24 +117,24 @@ package body System.Dwarf_Lines is
    --  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
+   --  Seek to the first byte of the first header 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 Parse_Header (C : in out Dwarf_Context);
+   --  Decode a DWARF statement program header
 
-   procedure Read_And_Execute_Isn
+   procedure Read_And_Execute_Insn
      (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
+      File :        uint32) return String;
+   --  Extract a file name from the header
 
    type Callback is not null access procedure (C : in out Dwarf_Context);
    procedure For_Each_Row (C : in out Dwarf_Context; F : Callback);
@@ -158,8 +164,25 @@ package body System.Dwarf_Lines is
    --  DWARF constants  --
    -----------------------
 
+   --  3.1.1 Full and Partial Compilation Unit Entries
+
+   DW_TAG_Compile_Unit : constant := 16#11#;
+
+   DW_AT_Stmt_List : constant := 16#10#;
+
+   --  6.2.4.1 Standard Content Descriptions (DWARF 5)
+
+   DW_LNCT_path            : constant := 1;
+   DW_LNCT_directory_index : constant := 2;
+   --  DW_LNCT_timestamp   : constant := 3;
+   --  DW_LNCT_size        : constant := 4;
+   DW_LNCT_MD5             : constant := 5;
+   DW_LNCT_lo_user         : constant := 16#2000#;
+   DW_LNCT_hi_user         : constant := 16#3fff#;
+
    --  6.2.5.2 Standard Opcodes
 
+   DW_LNS_extended_op        : constant := 0;
    DW_LNS_copy               : constant := 1;
    DW_LNS_advance_pc         : constant := 2;
    DW_LNS_advance_line       : constant := 3;
@@ -175,45 +198,56 @@ package body System.Dwarf_Lines is
 
    --  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_end_sequence      : constant := 1;
+   DW_LNE_set_address       : constant := 2;
+   DW_LNE_define_file       : constant := 3;
    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#;
+   --  7.5.5 Classes and Forms
+
+   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_strx           : constant := 16#1a#;
+   DW_FORM_addrx          : constant := 16#1b#;
+   DW_FORM_ref_sup4       : constant := 16#1c#;
+   DW_FORM_strp_sup       : constant := 16#1d#;
+   DW_FORM_data16         : constant := 16#1e#;
+   DW_FORM_line_strp      : constant := 16#1f#;
+   DW_FORM_ref_sig8       : constant := 16#20#;
+   DW_FORM_implicit_const : constant := 16#21#;
+   DW_FORM_loclistx       : constant := 16#22#;
+   DW_FORM_rnglistx       : constant := 16#23#;
+   DW_FORM_ref_sup8       : constant := 16#24#;
+   DW_FORM_strx1          : constant := 16#25#;
+   DW_FORM_strx2          : constant := 16#26#;
+   DW_FORM_strx3          : constant := 16#27#;
+   DW_FORM_strx4          : constant := 16#28#;
+   DW_FORM_addrx1         : constant := 16#29#;
+   DW_FORM_addrx2         : constant := 16#2a#;
+   DW_FORM_addrx3         : constant := 16#2b#;
+   DW_FORM_addrx4         : constant := 16#2c#;
 
    ---------
    -- "<" --
@@ -235,6 +269,7 @@ package body System.Dwarf_Lines is
       procedure Unchecked_Deallocation is new Ada.Unchecked_Deallocation
         (Search_Array,
          Search_Array_Access);
+
    begin
       if C.Has_Debug then
          Close (C.Lines);
@@ -265,6 +300,7 @@ package body System.Dwarf_Lines is
    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);
 
@@ -286,11 +322,13 @@ package body System.Dwarf_Lines 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
          declare
             E : Search_Entry renames Cache (I);
@@ -322,7 +360,7 @@ package body System.Dwarf_Lines is
       Initialize_Pass (C);
 
       loop
-         Read_And_Execute_Isn (C, Done);
+         Read_And_Execute_Insn (C, Done);
 
          if C.Registers.Is_Row then
             F.all (C);
@@ -339,8 +377,7 @@ package body System.Dwarf_Lines is
    procedure Initialize_Pass (C : in out Dwarf_Context) is
    begin
       Seek (C.Lines, 0);
-      C.Next_Prologue := 0;
-
+      C.Next_Header := 0;
       Initialize_State_Machine (C);
    end Initialize_Pass;
 
@@ -350,17 +387,16 @@ package body System.Dwarf_Lines is
 
    procedure Initialize_State_Machine (C : in out Dwarf_Context) is
    begin
+      --  Table 6.4: Line number program initial state
+
       C.Registers :=
         (Address        => 0,
          File           => 1,
          Line           => 1,
          Column         => 0,
-         Is_Stmt        => C.Prologue.Default_Is_Stmt = 0,
+         Is_Stmt        => C.Header.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;
 
@@ -378,8 +414,7 @@ package body System.Dwarf_Lines is
    -- Low_Address --
    -----------------
 
-   function Low_Address (C : Dwarf_Context)
-      return System.Address is
+   function Low_Address (C : Dwarf_Context) return System.Address is
    begin
       return C.Load_Address + C.Low;
    end Low_Address;
@@ -393,19 +428,24 @@ package body System.Dwarf_Lines is
       C         : out Dwarf_Context;
       Success   : out Boolean)
    is
-      Line_Sec, Info_Sec, Abbrev_Sec, Aranges_Sec : Object_Section;
-      Hi, Lo                                      : uint64;
+      Abbrev, Aranges, Lines, Info, Line_Str : Object_Section;
+      Hi, Lo                                 : uint64;
+
    begin
       --  Not a success by default
 
       Success := False;
 
-      --  Open file
+      --  Open file with In_Exception set so we can control the failure mode
 
-      C.Obj := Open (File_Name, C.In_Exception);
+      C.Obj := Open (File_Name, In_Exception => True);
 
       if C.Obj = null then
-         return;
+         if C.In_Exception then
+            return;
+         else
+            raise Dwarf_Error with "could not open file";
+         end if;
       end if;
 
       Success := True;
@@ -420,21 +460,23 @@ package body System.Dwarf_Lines is
       --  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");
+         Abbrev   := Get_Section (C.Obj.all, ".dwabrev");
+         Aranges  := Get_Section (C.Obj.all, ".dwarnge");
+         Info     := Get_Section (C.Obj.all, ".dwinfo");
+         Lines    := Get_Section (C.Obj.all, ".dwline");
+         Line_Str := Get_Section (C.Obj.all, ".dwlistr");
       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");
+         Abbrev   := Get_Section (C.Obj.all, ".debug_abbrev");
+         Aranges  := Get_Section (C.Obj.all, ".debug_aranges");
+         Info     := Get_Section (C.Obj.all, ".debug_info");
+         Lines    := Get_Section (C.Obj.all, ".debug_line");
+         Line_Str := Get_Section (C.Obj.all, ".debug_line_str");
       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
+      if Abbrev = Null_Section
+        or else Aranges = Null_Section
+        or else Info = Null_Section
+        or else Lines = Null_Section
       then
          pragma Annotate
            (CodePeer, False_Positive,
@@ -444,21 +486,29 @@ package body System.Dwarf_Lines is
          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);
+      C.Abbrev  := Create_Stream (C.Obj.all, Abbrev);
+      C.Aranges := Create_Stream (C.Obj.all, Aranges);
+      C.Info    := Create_Stream (C.Obj.all, Info);
+      C.Lines   := Create_Stream (C.Obj.all, Lines);
+
+      --  The .debug_line_str section may be available in DWARF 5
+
+      if Line_Str /= Null_Section then
+         C.Line_Str := Create_Stream (C.Obj.all, Line_Str);
+      end if;
 
       --  All operations are successful, context is valid
 
       C.Has_Debug := True;
    end Open;
 
-   --------------------
-   -- Parse_Prologue --
-   --------------------
+   ------------------
+   -- Parse_Header --
+   ------------------
+
+   procedure Parse_Header (C : in out Dwarf_Context) is
+      Header : Line_Info_Header renames C.Header;
 
-   procedure Parse_Prologue (C : in out Dwarf_Context) is
       Char : uint8;
       Prev : uint8;
       --  The most recently read character and the one preceding it
@@ -469,94 +519,147 @@ package body System.Dwarf_Lines is
       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);
+      First_Byte_Of_Header : Offset;
+      Last_Byte_Of_Header  : Offset;
 
-      Prologue : Line_Info_Prologue renames C.Prologue;
+      Standard_Opcode_Lengths : Opcode_Length_Array;
+      pragma Unreferenced (Standard_Opcode_Lengths);
 
    begin
-      Tell (C.Lines, First_Byte_Of_Prologue);
-      Prologue.Unit_Length := Read (C.Lines);
+      Tell (C.Lines, First_Byte_Of_Header);
+
+      Read_Initial_Length (C.Lines, Header.Unit_Length, Header.Is64);
+
       Tell (C.Lines, Off);
-      C.Next_Prologue := Off + Offset (Prologue.Unit_Length);
+      C.Next_Header := Off + Header.Unit_Length;
+
+      Header.Version := Read (C.Lines);
+
+      if Header.Version >= 5 then
+         Header.Address_Size          := Read (C.Lines);
+         Header.Segment_Selector_Size := Read (C.Lines);
+      else
+         Header.Address_Size          := 0;
+         Header.Segment_Selector_Size := 0;
+      end if;
 
-      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;
+      Header.Header_Length := Read (C.Lines);
+      Tell (C.Lines, Last_Byte_Of_Header);
+      Last_Byte_Of_Header :=
+        Last_Byte_Of_Header + Offset (Header.Header_Length) - 1;
 
-      Prologue.Min_Isn_Length := Read (C.Lines);
+      Header.Minimum_Insn_Length := Read (C.Lines);
 
-      if Prologue.Version >= 4 then
-         Max_Op_Per_Insn := Read (C.Lines);
+      if Header.Version >= 4 then
+         Header.Maximum_Op_Per_Insn := Read (C.Lines);
+      else
+         Header.Maximum_Op_Per_Insn := 0;
       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);
+      Header.Default_Is_Stmt := Read (C.Lines);
+      Header.Line_Base       := Read (C.Lines);
+      Header.Line_Range      := Read (C.Lines);
+      Header.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.
+      --  Standard_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);
+      for J in 1 .. Integer (Header.Opcode_Base - 1) loop
+         Standard_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.
+      --  The directories table follows. Up to DWARF 4, this is a list of null
+      --  terminated strings terminated by a null byte. In DWARF 5, this is a
+      --  sequence of Directories_Count entries encoded as described by the
+      --  Directory_Entry_Format field. We store its offset for later decoding.
 
-      Tell (C.Lines, Prologue.Includes_Offset);
-      Char := Read (C.Lines);
+      if Header.Version <= 4 then
+         Tell (C.Lines, Header.Directories);
+         Char := Read (C.Lines);
 
-      if Char /= 0 then
-         loop
-            Prev := Char;
-            Char := Read (C.Lines);
-            exit when Char = 0 and Prev = 0;
+         if Char /= 0 then
+            loop
+               Prev := Char;
+               Char := Read (C.Lines);
+               exit when Char = 0 and Prev = 0;
+            end loop;
+         end if;
+
+      else
+         Header.Directory_Entry_Format_Count := Read (C.Lines);
+         Read_Entry_Format_Array (C.Lines,
+           Header.Directory_Entry_Format,
+           Header.Directory_Entry_Format_Count);
+
+         Header.Directories_Count := Read_LEB128 (C.Lines);
+         Tell (C.Lines, Header.Directories);
+         for J in 1 .. Header.Directories_Count loop
+            for K in 1 .. Integer (Header.Directory_Entry_Format_Count) loop
+               Skip_Form (C.Lines,
+                 Header.Directory_Entry_Format (K).Form,
+                 Header.Is64,
+                 Header.Address_Size);
+            end loop;
          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.
+      --  The file_names table is next. Up to DWARF 4, this is a list of record
+      --  containing a null terminated string for the file name, an unsigned
+      --  LEB128 directory index in the Directories table, an unsigned LEB128
+      --  modification time, and an unsigned LEB128 for the file length; the
+      --  table is terminated by a null byte. In DWARF 5, this is a sequence
+      --  of File_Names_Count entries encoded as described by the
+      --  File_Name_Entry_Format field. We store its offset for later decoding.
 
-      Tell (C.Lines, Prologue.File_Names_Offset);
+      if Header.Version <= 4 then
+         Tell (C.Lines, Header.File_Names);
 
-      loop
-         --  Read the filename
+         --  Read the file names
 
-         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;
+         loop
+            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;
+
+      else
+         Header.File_Name_Entry_Format_Count := Read (C.Lines);
+         Read_Entry_Format_Array (C.Lines,
+           Header.File_Name_Entry_Format,
+           Header.File_Name_Entry_Format_Count);
+
+         Header.File_Names_Count := Read_LEB128 (C.Lines);
+         Tell (C.Lines, Header.File_Names);
+         for J in 1 .. Header.File_Names_Count loop
+            for K in 1 .. Integer (Header.File_Name_Entry_Format_Count) loop
+               Skip_Form (C.Lines,
+                 Header.File_Name_Entry_Format (K).Form,
+                 Header.Is64,
+                 Header.Address_Size);
+            end loop;
+         end loop;
+      end if;
 
       --  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.
+      --  the header ends where the header says it does. It we aren't, then we
+      --  have probably gotten out of sync somewhere.
 
       Tell (C.Lines, Off);
 
-      if Prologue.Unit_Length /= 0
-        and then Off /= Last_Byte_Of_Prologue + 1
+      if Header.Unit_Length /= 0
+        and then Off /= Last_Byte_Of_Header + 1
       then
-         raise Dwarf_Error with "Parse error reading DWARF information";
+         raise Dwarf_Error with "parse error reading DWARF information";
       end if;
-   end Parse_Prologue;
+   end Parse_Header;
 
-   --------------------------
-   -- Read_And_Execute_Isn --
-   --------------------------
+   ---------------------------
+   -- Read_And_Execute_Insn --
+   ---------------------------
 
-   procedure Read_And_Execute_Isn
+   procedure Read_And_Execute_Insn
      (C    : in out Dwarf_Context;
       Done :    out Boolean)
    is
@@ -572,7 +675,7 @@ package body System.Dwarf_Lines is
 
       Obj : Object_File renames C.Obj.all;
       Registers : Line_Info_Registers renames C.Registers;
-      Prologue : Line_Info_Prologue renames C.Prologue;
+      Header : Line_Info_Header renames C.Header;
 
    begin
       Done             := False;
@@ -582,8 +685,8 @@ package body System.Dwarf_Lines is
          Initialize_State_Machine (C);
       end if;
 
-      --  If we have reached the next prologue, read it. Beware of possibly
-      --  empty blocks.
+      --  If we have reached the next header, read it. Beware of possibly empty
+      --  blocks.
 
       --  When testing for the end of section, beware of possible zero padding
       --  at the end. Bail out as soon as there's not even room for at least a
@@ -592,9 +695,9 @@ package body System.Dwarf_Lines is
       --  or Off+3 > Section_Length.
 
       Tell (C.Lines, Off);
-      while Off = C.Next_Prologue loop
+      while Off = C.Next_Header loop
          Initialize_State_Machine (C);
-         Parse_Prologue (C);
+         Parse_Header (C);
          Tell (C.Lines, Off);
          exit when Off + 3 > Length (C.Lines);
       end loop;
@@ -606,7 +709,7 @@ package body System.Dwarf_Lines is
       --  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 + 3 > Length (C.Lines) then
+      if Header.Unit_Length = 0 or else Off + 3 > Length (C.Lines) then
          Done := True;
          return;
       end if;
@@ -617,7 +720,7 @@ package body System.Dwarf_Lines is
 
       --  Extended opcodes
 
-      if Opcode = 0 then
+      if Opcode = DW_LNS_extended_op then
          Extended_Length := Read_LEB128 (C.Lines);
          Extended_Opcode := Read (C.Lines);
 
@@ -656,7 +759,7 @@ package body System.Dwarf_Lines is
 
       --  Standard opcodes
 
-      elsif Opcode < Prologue.Opcode_Base then
+      elsif Opcode < Header.Opcode_Base then
          case Opcode is
 
             --  Append a row to the line info matrix
@@ -671,7 +774,7 @@ package body System.Dwarf_Lines is
                uint32_Operand    := Read_LEB128 (C.Lines);
                Registers.Address :=
                  Registers.Address +
-                 uint64 (uint32_Operand * uint32 (Prologue.Min_Isn_Length));
+                 uint64 (uint32_Operand * uint32 (Header.Minimum_Insn_Length));
 
             --  Add a signed word to the current source line
 
@@ -708,8 +811,8 @@ package body System.Dwarf_Lines is
                Registers.Address :=
                  Registers.Address +
                  uint64
-                   (((255 - Prologue.Opcode_Base) / Prologue.Line_Range) *
-                    Prologue.Min_Isn_Length);
+                   (((255 - Header.Opcode_Base) / Header.Line_Range) *
+                    Header.Minimum_Insn_Length);
 
             --  Advance the program counter by a constant
 
@@ -744,7 +847,7 @@ package body System.Dwarf_Lines is
             Line_Increment    : int32;
 
          begin
-            Opcode := Opcode - Prologue.Opcode_Base;
+            Opcode := Opcode - Header.Opcode_Base;
 
             --  The adjusted opcode is a uint8 encoding an address increment
             --  and a signed line increment. The upperbound is allowed to be
@@ -752,18 +855,16 @@ package body System.Dwarf_Lines is
             --  prevent overflows.
 
             Address_Increment :=
-              int32 (Opcode / Prologue.Line_Range) *
-              int32 (Prologue.Min_Isn_Length);
+              int32 (Opcode / Header.Line_Range) *
+              int32 (Header.Minimum_Insn_Length);
             Line_Increment :=
-              int32 (Prologue.Line_Base) +
-              int32 (Opcode mod Prologue.Line_Range);
+              int32 (Header.Line_Base) +
+              int32 (Opcode mod Header.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;
@@ -775,7 +876,7 @@ package body System.Dwarf_Lines is
 
          Registers.Is_Row := False;
          Done             := True;
-   end Read_And_Execute_Isn;
+   end Read_And_Execute_Insn;
 
    ----------------------
    -- Set_Load_Address --
@@ -792,10 +893,10 @@ package body System.Dwarf_Lines is
 
    function To_File_Name
      (C    : in out Dwarf_Context;
-      Code :        uint32) return String
+      File :        uint32) return String
    is
       Buf : Buffer;
-      J   : uint32;
+      Off : Offset;
 
       Dir_Idx : uint32;
       pragma Unreferenced (Dir_Idx);
@@ -806,25 +907,56 @@ package body System.Dwarf_Lines is
       Length : uint32;
       pragma Unreferenced (Length);
 
+      File_Entry_Format : Entry_Format_Array
+        renames C.Header.File_Name_Entry_Format;
+
    begin
-      Seek (C.Lines, C.Prologue.File_Names_Offset);
+      Seek (C.Lines, C.Header.File_Names);
 
-      --  Find the entry
+      --  Find the entry. Note that, up to DWARF 4, the index is 1-based
+      --  whereas, in DWARF 5, it is 0-based.
 
-      J := 0;
-      loop
-         J := J + 1;
-         Read_C_String (C.Lines, Buf);
+      if C.Header.Version <= 4 then
+         for J in 1 .. File loop
+            Read_C_String (C.Lines, Buf);
 
-         if Buf (Buf'First) = 0 then
-            return "???";
-         end if;
+            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;
+            Dir_Idx  := Read_LEB128 (C.Lines);
+            Mod_Time := Read_LEB128 (C.Lines);
+            Length   := Read_LEB128 (C.Lines);
+         end loop;
+
+      --  DWARF 5
+
+      else
+         for J in 0 .. File loop
+            for K in 1 .. Integer (C.Header.File_Name_Entry_Format_Count) loop
+               if File_Entry_Format (K).C_Type = DW_LNCT_path then
+                  case File_Entry_Format (K).Form is
+                     when DW_FORM_string =>
+                        Read_C_String (C.Lines, Buf);
+
+                     when DW_FORM_line_strp =>
+                        Read_Section_Offset (C.Lines, Off, C.Header.Is64);
+                        Seek (C.Line_Str, Off);
+                        Read_C_String (C.Line_Str, Buf);
+
+                     when others =>
+                        raise Dwarf_Error with "DWARF form not implemented";
+                  end case;
+
+               else
+                  Skip_Form (C.Lines,
+                    File_Entry_Format (K).Form,
+                    C.Header.Is64,
+                    C.Header.Address_Size);
+               end if;
+            end loop;
+         end loop;
+      end if;
 
       return To_String (Buf);
    end To_File_Name;
@@ -840,6 +972,7 @@ package body System.Dwarf_Lines is
    is
       Len32 : uint32;
       Len64 : uint64;
+
    begin
       Len32 := Read (S);
       if Len32 < 16#ffff_fff0# then
@@ -872,6 +1005,43 @@ package body System.Dwarf_Lines is
       end if;
    end Read_Section_Offset;
 
+   -----------------------------
+   -- Read_Entry_Format_Array --
+   -----------------------------
+
+   procedure Read_Entry_Format_Array
+     (S    : in out Mapped_Stream;
+      A    :    out Entry_Format_Array;
+      Len  :        uint8)
+   is
+      C_Type, Form : uint32;
+      N            : Integer;
+
+   begin
+      N := A'First;
+
+      for J in 1 .. Len loop
+         C_Type := Read_LEB128 (S);
+         Form   := Read_LEB128 (S);
+
+         case C_Type is
+            when DW_LNCT_path .. DW_LNCT_MD5 =>
+               if N not in A'Range then
+                  raise Dwarf_Error with "DWARF duplicate content type";
+               end if;
+
+               A (N) := (C_Type, Form);
+               N := N + 1;
+
+            when DW_LNCT_lo_user .. DW_LNCT_hi_user =>
+               null;
+
+            when others =>
+               raise Dwarf_Error with "DWARF content type not implemented";
+         end case;
+      end loop;
+   end Read_Entry_Format_Array;
+
    --------------------
    -- Aranges_Lookup --
    --------------------
@@ -921,31 +1091,53 @@ package body System.Dwarf_Lines is
       Ptr_Sz :        uint8)
    is
       Skip : Offset;
+
    begin
+      --  7.5.5 Classes and Forms
+
       case Form is
          when DW_FORM_addr =>
             Skip := Offset (Ptr_Sz);
+         when DW_FORM_addrx =>
+            Skip := Offset (uint32'(Read_LEB128 (S)));
+         when DW_FORM_block1 =>
+            Skip := Offset (uint8'(Read (S)));
          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 =>
+         when DW_FORM_addrx1
+            | DW_FORM_data1
+            | DW_FORM_flag
+            | DW_FORM_ref1
+            | DW_FORM_strx1
+           =>
             Skip := 1;
+         when DW_FORM_addrx2
+            | DW_FORM_data2
+            | DW_FORM_ref2
+            | DW_FORM_strx2
+           =>
+            Skip := 2;
+         when DW_FORM_addrx3 | DW_FORM_strx3 =>
+            Skip := 3;
+         when DW_FORM_addrx4
+            | DW_FORM_data4
+            | DW_FORM_ref4
+            | DW_FORM_ref_sup4
+            | DW_FORM_strx4
+           =>
+            Skip := 4;
+         when DW_FORM_data8
+            | DW_FORM_ref8
+            | DW_FORM_ref_sup8
+            | DW_FORM_ref_sig8
+           =>
+            Skip := 8;
+         when DW_FORM_data16 =>
+            Skip := 16;
          when DW_FORM_sdata =>
             declare
                Val : constant int32 := Read_LEB128 (S);
@@ -953,9 +1145,12 @@ package body System.Dwarf_Lines is
             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 =>
+         when DW_FORM_udata
+            | DW_FORM_ref_udata
+            | DW_FORM_loclistx
+            | DW_FORM_rnglistx
+            | DW_FORM_strx
+           =>
             declare
                Val : constant uint32 := Read_LEB128 (S);
                pragma Unreferenced (Val);
@@ -964,11 +1159,24 @@ package body System.Dwarf_Lines is
             end;
          when DW_FORM_flag_present =>
             return;
-         when DW_FORM_indirect =>
+         when DW_FORM_ref_addr
+            | DW_FORM_sec_offset
+            | DW_FORM_strp
+            | DW_FORM_line_strp
+            | DW_FORM_strp_sup
+           =>
+            Skip := (if Is64 then 8 else 4);
+         when DW_FORM_string =>
+            while uint8'(Read (S)) /= 0 loop
+               null;
+            end loop;
+            return;
+         when DW_FORM_implicit_const | DW_FORM_indirect =>
             raise Constraint_Error;
          when others =>
             raise Constraint_Error;
       end case;
+
       Seek (S, Tell (S) + Skip);
    end Skip_Form;
 
@@ -981,20 +1189,21 @@ package body System.Dwarf_Lines is
       Abbrev_Offset :        Offset;
       Abbrev_Num    :        uint32)
    is
-      Num       : uint32;
       Abbrev    : uint32;
       Tag       : uint32;
       Has_Child : uint8;
-      pragma Unreferenced (Abbrev, Tag, Has_Child);
+      pragma Unreferenced (Tag, Has_Child);
+
    begin
       Seek (C.Abbrev, Abbrev_Offset);
 
-      Num := 1;
+      --  7.5.3 Abbreviations Tables
 
       loop
-         exit when Num = Abbrev_Num;
+         Abbrev := Read_LEB128 (C.Abbrev);
+
+         exit when Abbrev = Abbrev_Num;
 
-         Abbrev    := Read_LEB128 (C.Abbrev);
          Tag       := Read_LEB128 (C.Abbrev);
          Has_Child := Read (C.Abbrev);
 
@@ -1002,12 +1211,19 @@ package body System.Dwarf_Lines is
             declare
                Name : constant uint32 := Read_LEB128 (C.Abbrev);
                Form : constant uint32 := Read_LEB128 (C.Abbrev);
+               Cst  : int32;
+               pragma Unreferenced (Cst);
+
             begin
-               exit when Name = 0 and Form = 0;
+               --  DW_FORM_implicit_const takes its value from the table
+
+               if Form = DW_FORM_implicit_const then
+                  Cst := Read_LEB128 (C.Abbrev);
+               end if;
+
+               exit when Name = 0 and then Form = 0;
             end;
          end loop;
-
-         Num := Num + 1;
       end loop;
    end Seek_Abbrev;
 
@@ -1029,23 +1245,40 @@ package body System.Dwarf_Lines is
       Abbrev        : uint32;
       Has_Child     : uint8;
       pragma Unreferenced (Has_Child);
+      Unit_Type     : uint8;
+      pragma Unreferenced (Unit_Type);
+
    begin
       Line_Offset := 0;
       Success := False;
 
       Seek (C.Info, Info_Offset);
 
+      --  7.5.1.1 Compilation Unit Header
+
       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);
+      if Version >= 5 then
+         Unit_Type := Read (C.Info);
+
+         Addr_Sz := Read (C.Info);
+         if Addr_Sz /= (Address'Size / SSU) then
+            return;
+         end if;
+
+         Read_Section_Offset (C.Info, Abbrev_Offset, Is64);
+
+      elsif Version >= 2 then
+         Read_Section_Offset (C.Info, Abbrev_Offset, Is64);
+
+         Addr_Sz := Read (C.Info);
+         if Addr_Sz /= (Address'Size / SSU) then
+            return;
+         end if;
 
-      Addr_Sz := Read (C.Info);
-      if Addr_Sz /= (Address'Size / SSU) then
+      else
          return;
       end if;
 
@@ -1060,17 +1293,9 @@ package body System.Dwarf_Lines is
 
       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;
 
@@ -1104,8 +1329,6 @@ package body System.Dwarf_Lines is
             end if;
          end;
       end loop;
-
-      return;
    end Debug_Info_Lookup;
 
    -------------------------
@@ -1121,6 +1344,7 @@ package body System.Dwarf_Lines is
       Is64        : Boolean;
       Version     : uint16;
       Sz          : uint8;
+
    begin
       Success     := False;
       Info_Offset := 0;
@@ -1149,6 +1373,7 @@ package body System.Dwarf_Lines is
       end if;
 
       --  Handle alignment on twice the address size
+
       declare
          Cur_Off : constant Offset := Tell (C.Aranges);
          Align   : constant Offset := 2 * Address'Size / SSU;
@@ -1173,6 +1398,7 @@ package body System.Dwarf_Lines is
    is
    begin
       --  Read table
+
       if Address'Size = 32 then
          declare
             S, L : uint32;
@@ -1182,6 +1408,7 @@ package body System.Dwarf_Lines is
             Start := Storage_Offset (S);
             Len   := Storage_Count (L);
          end;
+
       elsif Address'Size = 64 then
          declare
             S, L : uint64;
@@ -1191,6 +1418,7 @@ package body System.Dwarf_Lines is
             Start := Storage_Offset (S);
             Len   := Storage_Count (L);
          end;
+
       else
          raise Constraint_Error;
       end if;
@@ -1202,8 +1430,11 @@ package body System.Dwarf_Lines is
 
    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.
+      --  Phase 1: count number of symbols.
+      --  Phase 2: fill the cache.
+
       declare
          S               : Object_Symbol;
          Val             : uint64;
@@ -1220,6 +1451,7 @@ package body System.Dwarf_Lines is
             while S /= Null_Symbol loop
                --  Discard symbols of length 0 or located outside of the
                --  execution code section outer boundaries.
+
                Sz := uint32 (Size (S));
                Val := Value (S);
 
@@ -1227,11 +1459,11 @@ package body System.Dwarf_Lines is
                  and then Val >= Xcode_Low
                  and then Val <= Xcode_High
                then
-
                   Addr := uint32 (Val - Xcode_Low);
 
                   --  Try to filter symbols at the same address. This is a best
                   --  effort as they might not be consecutive.
+
                   if Addr /= Prev_Addr then
                      Nbr_Symbols := Nbr_Symbols + 1;
                      Prev_Addr   := Addr;
@@ -1251,6 +1483,7 @@ package body System.Dwarf_Lines is
 
             if Phase = 1 then
                --  Allocate the cache
+
                Cache   := new Search_Array (1 .. Nbr_Symbols);
                C.Cache := Cache;
             end if;
@@ -1258,13 +1491,16 @@ package body System.Dwarf_Lines is
          pragma Assert (Nbr_Symbols = C.Cache'Last);
       end;
 
-      --  Sort the cache.
+      --  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;
@@ -1285,6 +1521,7 @@ package body System.Dwarf_Lines is
             exit when not Success;
 
             --  Read table
+
             loop
                Read_Aranges_Entry (C, Ar_Start, Ar_Len);
                exit when Ar_Start = 0 and Ar_Len = 0;
@@ -1293,6 +1530,7 @@ package body System.Dwarf_Lines is
                Start := uint32 (Ar_Start - C.Low);
 
                --  Search START in the array
+
                First := Cache'First;
                Last  := Cache'Last;
                Mid := First;  --  In case of array with one element
@@ -1307,9 +1545,10 @@ package body System.Dwarf_Lines is
                   end if;
                end loop;
 
-               --  Fill info.
+               --  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
@@ -1321,9 +1560,11 @@ package body System.Dwarf_Lines is
                     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;
@@ -1350,7 +1591,7 @@ package body System.Dwarf_Lines is
 
       procedure Set_Result (Match : Line_Info_Registers) is
          Dir_Idx : uint32;
-         J       : uint32;
+         Off     : Offset;
 
          Mod_Time : uint32;
          pragma Unreferenced (Mod_Time);
@@ -1358,46 +1599,123 @@ package body System.Dwarf_Lines is
          Length : uint32;
          pragma Unreferenced (Length);
 
+         Directory_Entry_Format : Entry_Format_Array
+           renames C.Header.Directory_Entry_Format;
+
+         File_Entry_Format : Entry_Format_Array
+           renames C.Header.File_Name_Entry_Format;
+
       begin
-         Seek (C.Lines, C.Prologue.File_Names_Offset);
+         Seek (C.Lines, C.Header.File_Names);
+         Dir_Idx := 0;
 
-         --  Find the entry
+         --  Find the entry. Note that, up to DWARF 4, the index is 1-based
+         --  whereas, in DWARF 5, it is 0-based.
 
-         J := 0;
-         loop
-            J         := J + 1;
-            File_Name := Read_C_String (C.Lines);
+         if C.Header.Version <= 4 then
+            for J in 1 .. Match.File loop
+               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;
+               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;
+               Dir_Idx  := Read_LEB128 (C.Lines);
+               Mod_Time := Read_LEB128 (C.Lines);
+               Length   := Read_LEB128 (C.Lines);
+            end loop;
+
+            if Dir_Idx = 0 then
+               --  No directory
+
+               Dir_Name := null;
+
+            else
+               Seek (C.Lines, C.Header.Directories);
+
+               for J in 1 .. Dir_Idx loop
+                  Dir_Name := Read_C_String (C.Lines);
 
-         if Dir_Idx = 0 then
-            --  No directory
-            Dir_Name := null;
+                  if Dir_Name (Dir_Name'First) = ASCII.NUL then
+                     --  End of directory list, so ill-formed table
+
+                     return;
+                  end if;
+               end loop;
+            end if;
+
+         --  DWARF 5
 
          else
-            Seek (C.Lines, C.Prologue.Includes_Offset);
+            for J in 0 .. Match.File loop
+               for K in 1 .. Integer (C.Header.File_Name_Entry_Format_Count)
+               loop
+                  if File_Entry_Format (K).C_Type = DW_LNCT_path then
+                     case File_Entry_Format (K).Form is
+                        when DW_FORM_string =>
+                           File_Name := Read_C_String (C.Lines);
 
-            J := 0;
-            loop
-               J        := J + 1;
-               Dir_Name := Read_C_String (C.Lines);
+                        when DW_FORM_line_strp =>
+                           Read_Section_Offset (C.Lines, Off, C.Header.Is64);
+                           Seek (C.Line_Str, Off);
+                           File_Name := Read_C_String (C.Line_Str);
 
-               if Dir_Name (Dir_Name'First) = ASCII.NUL then
-                  --  End of directory list, so ill-formed table
-                  return;
-               end if;
+                        when others =>
+                           raise Dwarf_Error with "DWARF form not implemented";
+                     end case;
+
+                  elsif File_Entry_Format (K).C_Type = DW_LNCT_directory_index
+                  then
+                     case File_Entry_Format (K).Form is
+                        when DW_FORM_data1 =>
+                           Dir_Idx := uint32 (uint8'(Read (C.Lines)));
+
+                        when DW_FORM_data2 =>
+                           Dir_Idx := uint32 (uint16'(Read (C.Lines)));
+
+                        when DW_FORM_udata =>
+                           Dir_Idx := Read_LEB128 (C.Lines);
 
-               exit when J = Dir_Idx;
+                        when others =>
+                           raise Dwarf_Error with "invalid DWARF";
+                     end case;
 
+                  else
+                     Skip_Form (C.Lines,
+                       File_Entry_Format (K).Form,
+                       C.Header.Is64,
+                       C.Header.Address_Size);
+                  end if;
+               end loop;
+            end loop;
+
+            Seek (C.Lines, C.Header.Directories);
+
+            for J in 0 .. Dir_Idx loop
+               for K in 1 .. Integer (C.Header.Directory_Entry_Format_Count)
+               loop
+                  if Directory_Entry_Format (K).C_Type = DW_LNCT_path then
+                     case Directory_Entry_Format (K).Form is
+                        when DW_FORM_string =>
+                           Dir_Name := Read_C_String (C.Lines);
+
+                        when DW_FORM_line_strp =>
+                           Read_Section_Offset (C.Lines, Off, C.Header.Is64);
+                           Seek (C.Line_Str, Off);
+                           Dir_Name := Read_C_String (C.Line_Str);
+
+                        when others =>
+                           raise Dwarf_Error with "DWARF form not implemented";
+                     end case;
+
+                  else
+                     Skip_Form (C.Lines,
+                       Directory_Entry_Format (K).Form,
+                       C.Header.Is64,
+                       C.Header.Address_Size);
+                  end if;
+               end loop;
             end loop;
          end if;
 
@@ -1414,13 +1732,15 @@ package body System.Dwarf_Lines is
 
    begin
       --  Initialize result
+
       Dir_Name    := null;
       File_Name   := null;
       Subprg_Name := (null, 0);
       Line_Num    := 0;
 
+      --  Look up the symbol in the cache
+
       if C.Cache /= null then
-         --  Look in the cache
          declare
             Addr_Off         : constant uint32 := uint32 (Addr - C.Low);
             First, Last, Mid : Natural;
@@ -1447,12 +1767,13 @@ package body System.Dwarf_Lines is
                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;
+
+      --  Search for the symbol in the binary
+
       else
-         --  Search symbol
          S := First_Symbol (C.Obj.all);
          while S /= Null_Symbol loop
             if Spans (S, Addr_Int) then
@@ -1479,15 +1800,15 @@ package body System.Dwarf_Lines is
       end if;
 
       Seek (C.Lines, Line_Offset);
-      C.Next_Prologue := 0;
+      C.Next_Header := 0;
       Initialize_State_Machine (C);
-      Parse_Prologue (C);
+      Parse_Header (C);
       Previous_Row.Line := 0;
 
       --  Advance to the first entry
 
       loop
-         Read_And_Execute_Isn (C, Done);
+         Read_And_Execute_Insn (C, Done);
 
          if C.Registers.Is_Row then
             Previous_Row := C.Registers;
@@ -1499,8 +1820,8 @@ package body System.Dwarf_Lines is
 
       --  Read the rest of the entries
 
-      while Tell (C.Lines) < C.Next_Prologue loop
-         Read_And_Execute_Isn (C, Done);
+      while Tell (C.Lines) < C.Next_Header loop
+         Read_And_Execute_Insn (C, Done);
 
          if C.Registers.Is_Row then
             if not Previous_Row.End_Sequence
@@ -1533,6 +1854,7 @@ package body System.Dwarf_Lines is
             return I - Str'First;
          end if;
       end loop;
+
       return Str'Last;
    end String_Length;
 
@@ -1558,6 +1880,7 @@ package body System.Dwarf_Lines is
       Subprg_Name : String_Ptr_Len;
       Line_Num    : Natural;
       Off         : Natural;
+
    begin
       if not C.Has_Debug then
          Symbol_Found := False;
@@ -1657,4 +1980,5 @@ package body System.Dwarf_Lines is
          Append (Res, ASCII.LF);
       end loop;
    end Symbolic_Traceback;
+
 end System.Dwarf_Lines;
diff --git a/gcc/ada/libgnat/s-dwalin.ads b/gcc/ada/libgnat/s-dwalin.ads
index c7bb1039542..132d3e1affa 100644
--- a/gcc/ada/libgnat/s-dwalin.ads
+++ b/gcc/ada/libgnat/s-dwalin.ads
@@ -30,13 +30,10 @@
 ------------------------------------------------------------------------------
 
 --  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.
+--  a binary 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.
+--  Files must be compiled with at least minimal debugging information (-g1).
 
 with Ada.Exceptions.Traceback;
 
@@ -50,11 +47,11 @@ package System.Dwarf_Lines is
    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.
+   --  Type encapsulating the state of the DWARF reader. When In_Exception is
+   --  True, we are parsing as part of an exception handler decorator so we do
+   --  not want another exception to be raised and the parsing is done safely,
+   --  skipping binary files that cannot be read or have been stripped from
+   --  their debug sections for example.
 
    procedure Open
      (File_Name :     String;
@@ -65,14 +62,13 @@ package System.Dwarf_Lines is
 
    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.
+   --  Independent Executable) binaries.
 
    function Is_Inside (C : Dwarf_Context; Addr : Address) return Boolean;
    pragma Inline (Is_Inside);
    --  Return true iff a run-time address Addr is within the module
 
-   function Low_Address (C : Dwarf_Context)
-      return System.Address;
+   function Low_Address (C : Dwarf_Context) return System.Address;
    pragma Inline (Low_Address);
    --  Return the lowest address of C, accounting for the module load address
 
@@ -83,7 +79,7 @@ package System.Dwarf_Lines is
    --  Dump the cache (if present)
 
    procedure Enable_Cache (C : in out Dwarf_Context);
-   --  Read symbols information to speed up Symbolic_Traceback.
+   --  Read symbol information to speed up Symbolic_Traceback.
 
    procedure Symbolic_Traceback
      (Cin          :        Dwarf_Context;
@@ -102,45 +98,64 @@ package System.Dwarf_Lines is
 private
    --  The following section numbers reference
 
-   --    "DWARF Debugging Information Format, Version 3"
+   --    "DWARF Debugging Information Format, Version 5"
 
    --  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;
+      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;
+      --  Discriminator  : SOR.uint32;  -- DWARF 4/5
+      Is_Row             : Boolean;     -- local
    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;
+   --  6.2.4 The Line Number Program Header
+
+   MAX_OPCODE : constant := 256;
+
+   type Opcode_Length_Array is array (1 .. MAX_OPCODE) of SOR.uint8;
+
+   MAX_ENTRY : constant := 5;
+
+   type Entry_Format_Pair is record
+      C_Type : SOR.uint32;
+      Form   : SOR.uint32;
+   end record;
+
+   type Entry_Format_Array is array (1 .. MAX_ENTRY) of Entry_Format_Pair;
+
+   type Line_Info_Header is record
+      Unit_Length                  : SOR.Offset;
+      Version                      : SOR.uint16;
+      Address_Size                 : SOR.uint8;           -- DWARF 5
+      Segment_Selector_Size        : SOR.uint8;           -- DWARF 5
+      Header_Length                : SOR.uint32;
+      Minimum_Insn_Length          : SOR.uint8;
+      Maximum_Op_Per_Insn          : SOR.uint8;           -- DWARF 4/5
+      Default_Is_Stmt              : SOR.uint8;
+      Line_Base                    : SOR.int8;
+      Line_Range                   : SOR.uint8;
+      Opcode_Base                  : SOR.uint8;
+      --  Standard_Opcode_Lengths  : Opcode_Length_Array;
+      Directory_Entry_Format_Count : SOR.uint8;           -- DWARF 5
+      Directory_Entry_Format       : Entry_Format_Array;  -- DWARF 5
+      Directories_Count            : SOR.uint32;          -- DWARF 5
+      Directories                  : SOR.Offset;
+      File_Name_Entry_Format_Count : SOR.uint8;           -- DWARF 5
+      File_Name_Entry_Format       : Entry_Format_Array;  -- DWARF 5
+      File_Names_Count             : SOR.uint32;          -- DWARF 5
+      File_Names                   : SOR.Offset;
+      Is64                         : Boolean;             -- local
    end record;
 
    type Search_Entry is record
@@ -175,15 +190,16 @@ private
       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
+      Abbrev   : SOR.Mapped_Stream;
+      Aranges  : SOR.Mapped_Stream;
+      Info     : SOR.Mapped_Stream;
+      Lines    : SOR.Mapped_Stream;
+      Line_Str : SOR.Mapped_Stream;  -- DWARF 5
+      --  DWARF sections
 
-      Prologue      : Line_Info_Prologue;
-      Registers     : Line_Info_Registers;
-      Next_Prologue : SOR.Offset;
+      Header      : Line_Info_Header;
+      Registers   : Line_Info_Registers;
+      Next_Header : SOR.Offset;
       --  State for lines
    end record;


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-07-12 12:51 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-12 12:51 [gcc r12-2248] [Ada] Add DWARF 5 support to System.Dwarf_Line Pierre-Marie de Rodat

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).