From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1285) id BD4DC385800A; Thu, 30 Sep 2021 11:47:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BD4DC385800A MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Eric Botcazou To: gcc-cvs@gcc.gnu.org Subject: [gcc r11-9040] [Ada] Add DWARF 5 support to System.Dwarf_Line X-Act-Checkin: gcc X-Git-Author: Eric Botcazou X-Git-Refname: refs/heads/releases/gcc-11 X-Git-Oldrev: 9fc6d71d34b9e75c573b311bc3b38caab6599704 X-Git-Newrev: e19a0e2f3071d89f8e55f15d9a8b644ffef8815a Message-Id: <20210930114752.BD4DC385800A@sourceware.org> Date: Thu, 30 Sep 2021 11:47:52 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 30 Sep 2021 11:47:52 -0000 https://gcc.gnu.org/g:e19a0e2f3071d89f8e55f15d9a8b644ffef8815a commit r11-9040-ge19a0e2f3071d89f8e55f15d9a8b644ffef8815a Author: Eric Botcazou 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 d8b15c5dd66..7135b7ab25d 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 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 072f089509e..77d3cdf71c9 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;