1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- S Y S T E M . T R A C E B A C K . S Y M B O L I C --
9 -- Copyright (C) 1999-2018, AdaCore --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 -- Run-time symbolic traceback support for targets using DWARF debug data
35 -- We must turn polling off for this unit, because otherwise we can get
36 -- elaboration circularities when polling is turned on.
38 with Ada
.Unchecked_Deallocation
;
40 with Ada
.Exceptions
.Traceback
; use Ada
.Exceptions
.Traceback
;
41 with Ada
.Containers
.Generic_Array_Sort
;
43 with System
.Address_To_Access_Conversions
;
44 with System
.Soft_Links
;
46 with System
.Dwarf_Lines
;
47 with System
.Exception_Traces
;
48 with System
.Standard_Library
;
49 with System
.Traceback_Entries
;
51 with System
.Bounded_Strings
;
53 package body System
.Traceback
.Symbolic
is
55 use System
.Bounded_Strings
;
56 use System
.Dwarf_Lines
;
58 subtype Big_String
is String (Positive);
59 -- To deal with C strings
61 package Big_String_Conv
is new System
.Address_To_Access_Conversions
65 type Module_Cache_Acc
is access all Module_Cache
;
67 type Module_Cache
is record
68 Name
: Strings
.String_Access
;
71 C
: Dwarf_Context
(In_Exception
=> True);
72 -- Context to symbolize an address within this module
74 Chain
: Module_Cache_Acc
;
77 procedure Free
is new Ada
.Unchecked_Deallocation
81 Cache_Chain
: Module_Cache_Acc
;
82 -- Simply linked list of modules
84 type Module_Array
is array (Natural range <>) of Module_Cache_Acc
;
85 type Module_Array_Acc
is access Module_Array
;
87 Modules_Cache
: Module_Array_Acc
;
88 -- Sorted array of cached modules (if not null)
90 Exec_Module
: aliased Module_Cache
;
91 -- Context for the executable
93 type Init_State
is (Uninitialized
, Initialized
, Failed
);
94 Exec_Module_State
: Init_State
:= Uninitialized
;
95 -- How Exec_Module is initialized
97 procedure Init_Exec_Module
;
98 -- Initialize Exec_Module if not already initialized
100 function Symbolic_Traceback
101 (Traceback
: System
.Traceback_Entries
.Tracebacks_Array
;
102 Suppress_Hex
: Boolean) return String;
103 function Symbolic_Traceback
104 (E
: Ada
.Exceptions
.Exception_Occurrence
;
105 Suppress_Hex
: Boolean) return String;
106 -- Suppress_Hex means do not print any hexadecimal addresses, even if the
107 -- symbol is not available.
109 function Lt
(Left
, Right
: Module_Cache_Acc
) return Boolean;
110 -- Sort function for Module_Cache
112 procedure Init_Module
113 (Module
: out Module_Cache
;
114 Success
: out Boolean;
115 Module_Name
: String;
116 Load_Address
: Address
:= Null_Address
);
119 procedure Close_Module
(Module
: in out Module_Cache
);
122 function Value
(Item
: System
.Address
) return String;
123 -- Return the String contained in Item, up until the first NUL character
125 pragma Warnings
(Off
, "*Add_Module_To_Cache*");
126 procedure Add_Module_To_Cache
(Module_Name
: String);
127 -- To be called by Build_Cache_For_All_Modules to add a new module to the
128 -- list. May not be referenced.
130 package Module_Name
is
132 procedure Build_Cache_For_All_Modules
;
133 -- Create the cache for all current modules
135 function Get
(Addr
: System
.Address
;
136 Load_Addr
: access System
.Address
) return String;
137 -- Returns the module name for the given address Addr, or an empty
138 -- string for the main executable. Load_Addr is set to the shared
139 -- library load address if this information is available, or to
140 -- System.Null_Address otherwise.
142 function Is_Supported
return Boolean;
143 pragma Inline
(Is_Supported
);
144 -- Returns True if Module_Name is supported, so if the traceback is
145 -- supported for shared libraries.
149 package body Module_Name
is separate;
151 function Executable_Name
return String;
152 -- Returns the executable name as reported by argv[0]. If gnat_argv not
153 -- initialized or if argv[0] executable not found in path, function returns
156 function Get_Executable_Load_Address
return System
.Address
;
159 Get_Executable_Load_Address
,
160 "__gnat_get_executable_load_address");
161 -- Get the load address of the executable, or Null_Address if not known
163 procedure Hexa_Traceback
164 (Traceback
: Tracebacks_Array
;
165 Suppress_Hex
: Boolean;
166 Res
: in out Bounded_String
);
167 -- Non-symbolic traceback (simply write addresses in hexa)
169 procedure Symbolic_Traceback_No_Lock
170 (Traceback
: Tracebacks_Array
;
171 Suppress_Hex
: Boolean;
172 Res
: in out Bounded_String
);
173 -- Like the public Symbolic_Traceback_No_Lock except there is no provision
174 -- against concurrent accesses.
176 procedure Module_Symbolic_Traceback
177 (Traceback
: Tracebacks_Array
;
178 Module
: Module_Cache
;
179 Suppress_Hex
: Boolean;
180 Res
: in out Bounded_String
);
181 -- Returns the Traceback for a given module
183 procedure Multi_Module_Symbolic_Traceback
184 (Traceback
: Tracebacks_Array
;
185 Suppress_Hex
: Boolean;
186 Res
: in out Bounded_String
);
187 -- Build string containing symbolic traceback for the given call chain
189 procedure Multi_Module_Symbolic_Traceback
190 (Traceback
: Tracebacks_Array
;
191 Module
: Module_Cache
;
192 Suppress_Hex
: Boolean;
193 Res
: in out Bounded_String
);
194 -- Likewise but using Module
196 Max_String_Length
: constant := 4096;
197 -- Arbitrary limit on Bounded_Str length
203 function Value
(Item
: System
.Address
) return String is
205 if Item
/= Null_Address
then
206 for J
in Big_String
'Range loop
207 if Big_String_Conv
.To_Pointer
(Item
) (J
) = ASCII
.NUL
then
208 return Big_String_Conv
.To_Pointer
(Item
) (1 .. J
- 1);
216 -------------------------
217 -- Add_Module_To_Cache --
218 -------------------------
220 procedure Add_Module_To_Cache
(Module_Name
: String) is
221 Module
: Module_Cache_Acc
;
224 Module
:= new Module_Cache
;
225 Init_Module
(Module
.all, Success
, Module_Name
);
230 Module
.Chain
:= Cache_Chain
;
231 Cache_Chain
:= Module
;
232 end Add_Module_To_Cache
;
234 ----------------------
235 -- Init_Exec_Module --
236 ----------------------
238 procedure Init_Exec_Module
is
240 if Exec_Module_State
= Uninitialized
then
242 Exec_Path
: constant String := Executable_Name
;
243 Exec_Load
: constant Address
:= Get_Executable_Load_Address
;
246 Init_Module
(Exec_Module
, Success
, Exec_Path
, Exec_Load
);
249 Exec_Module_State
:= Initialized
;
251 Exec_Module_State
:= Failed
;
255 end Init_Exec_Module
;
261 function Lt
(Left
, Right
: Module_Cache_Acc
) return Boolean is
263 return Low
(Left
.C
) < Low
(Right
.C
);
266 -----------------------------
267 -- Module_Cache_Array_Sort --
268 -----------------------------
270 procedure Module_Cache_Array_Sort
is new Ada
.Containers
.Generic_Array_Sort
280 procedure Enable_Cache
(Include_Modules
: Boolean := False) is
282 -- Can be called at most once
283 if Cache_Chain
/= null then
289 Cache_Chain
:= Exec_Module
'Access;
291 if Include_Modules
then
292 Module_Name
.Build_Cache_For_All_Modules
;
295 -- Build and fill the array of modules
298 Module
: Module_Cache_Acc
;
300 for Phase
in 1 .. 2 loop
302 Module
:= Cache_Chain
;
303 while Module
/= null loop
307 Enable_Cache
(Module
.C
);
309 Modules_Cache
(Count
) := Module
;
311 Module
:= Module
.Chain
;
315 Modules_Cache
:= new Module_Array
(1 .. Count
);
321 Module_Cache_Array_Sort
(Modules_Cache
.all);
324 ---------------------
325 -- Executable_Name --
326 ---------------------
328 function Executable_Name
return String is
329 -- We have to import gnat_argv as an Address to match the type of
330 -- gnat_argv in the binder generated file. Otherwise, we get spurious
331 -- warnings about type mismatch when LTO is turned on.
333 Gnat_Argv
: System
.Address
;
334 pragma Import
(C
, Gnat_Argv
, "gnat_argv");
336 type Argv_Array
is array (0 .. 0) of System
.Address
;
337 package Conv
is new System
.Address_To_Access_Conversions
(Argv_Array
);
339 function locate_exec_on_path
(A
: System
.Address
) return System
.Address
;
340 pragma Import
(C
, locate_exec_on_path
, "__gnat_locate_exec_on_path");
343 if Gnat_Argv
= Null_Address
then
348 Addr
: constant System
.Address
:=
349 locate_exec_on_path
(Conv
.To_Pointer
(Gnat_Argv
) (0));
350 Result
: constant String := Value
(Addr
);
353 -- The buffer returned by locate_exec_on_path was allocated using
354 -- malloc, so we should use free to release the memory.
356 if Addr
/= Null_Address
then
357 System
.CRTL
.free
(Addr
);
368 procedure Close_Module
(Module
: in out Module_Cache
) is
371 Strings
.Free
(Module
.Name
);
378 procedure Init_Module
379 (Module
: out Module_Cache
;
380 Success
: out Boolean;
381 Module_Name
: String;
382 Load_Address
: Address
:= Null_Address
)
385 -- Early return if the module is not known
387 if Module_Name
= "" then
392 Open
(Module_Name
, Module
.C
, Success
);
394 -- If a module can't be opened just return now, we just cannot give more
395 -- information in this case.
401 Set_Load_Address
(Module
.C
, Load_Address
);
403 Module
.Name
:= new String'(Module_Name);
406 -------------------------------
407 -- Module_Symbolic_Traceback --
408 -------------------------------
410 procedure Module_Symbolic_Traceback
411 (Traceback : Tracebacks_Array;
412 Module : Module_Cache;
413 Suppress_Hex : Boolean;
414 Res : in out Bounded_String)
416 Success : Boolean := False;
418 if Symbolic.Module_Name.Is_Supported then
420 Append (Res, Module.Name.all);
421 Append (Res, ']' & ASCII.LF);
424 Dwarf_Lines.Symbolic_Traceback
432 Hexa_Traceback (Traceback, Suppress_Hex, Res);
435 -- We must not allow an unhandled exception here, since this function
436 -- may be installed as a decorator for all automatic exceptions.
441 end Module_Symbolic_Traceback;
443 -------------------------------------
444 -- Multi_Module_Symbolic_Traceback --
445 -------------------------------------
447 procedure Multi_Module_Symbolic_Traceback
448 (Traceback : Tracebacks_Array;
449 Suppress_Hex : Boolean;
450 Res : in out Bounded_String)
452 F : constant Natural := Traceback'First;
454 if Traceback'Length = 0 or else Is_Full (Res) then
458 if Modules_Cache /= null then
459 -- Search in the cache
462 Addr : constant Address := Traceback (F);
463 Hi, Lo, Mid : Natural;
465 Lo := Modules_Cache'First;
466 Hi := Modules_Cache'Last;
468 Mid := (Lo + Hi) / 2;
469 if Addr < Low (Modules_Cache (Mid).C) then
471 elsif Is_Inside (Modules_Cache (Mid).C, Addr) then
472 Multi_Module_Symbolic_Traceback
474 Modules_Cache (Mid).all,
484 Hexa_Traceback (Traceback (F .. F), Suppress_Hex, Res);
485 Multi_Module_Symbolic_Traceback
486 (Traceback (F + 1 .. Traceback'Last),
492 -- First try the executable
493 if Is_Inside (Exec_Module.C, Traceback (F)) then
494 Multi_Module_Symbolic_Traceback
502 -- Otherwise, try a shared library
504 Load_Addr : aliased System.Address;
505 M_Name : constant String :=
506 Module_Name.Get (Addr => Traceback (F),
507 Load_Addr => Load_Addr'Access);
508 Module : Module_Cache;
511 Init_Module (Module, Success, M_Name, Load_Addr);
513 Multi_Module_Symbolic_Traceback
518 Close_Module (Module);
521 Hexa_Traceback (Traceback (F .. F), Suppress_Hex, Res);
522 Multi_Module_Symbolic_Traceback
523 (Traceback (F + 1 .. Traceback'Last),
529 end Multi_Module_Symbolic_Traceback;
531 procedure Multi_Module_Symbolic_Traceback
532 (Traceback : Tracebacks_Array;
533 Module : Module_Cache;
534 Suppress_Hex : Boolean;
535 Res : in out Bounded_String)
539 -- Will symbolize the first address...
541 Pos := Traceback'First + 1;
543 -- ... and all addresses in the same module
547 exit Same_Module when Pos > Traceback'Last;
549 -- Get address to check for corresponding module name
551 exit Same_Module when not Is_Inside (Module.C, Traceback (Pos));
554 end loop Same_Module;
556 Module_Symbolic_Traceback
557 (Traceback (Traceback'First .. Pos - 1),
561 Multi_Module_Symbolic_Traceback
562 (Traceback (Pos .. Traceback'Last),
565 end Multi_Module_Symbolic_Traceback;
571 procedure Hexa_Traceback
572 (Traceback : Tracebacks_Array;
573 Suppress_Hex : Boolean;
574 Res : in out Bounded_String)
576 use System.Traceback_Entries;
580 Append (Res, ASCII.LF);
582 for J in Traceback'Range loop
583 Append_Address (Res, PC_For (Traceback (J)));
584 Append (Res, ASCII.LF);
589 --------------------------------
590 -- Symbolic_Traceback_No_Lock --
591 --------------------------------
593 procedure Symbolic_Traceback_No_Lock
594 (Traceback : Tracebacks_Array;
595 Suppress_Hex : Boolean;
596 Res : in out Bounded_String)
599 if Symbolic.Module_Name.Is_Supported then
600 Multi_Module_Symbolic_Traceback (Traceback, Suppress_Hex, Res);
602 if Exec_Module_State = Failed then
603 Append (Res, "Call stack traceback locations:" & ASCII.LF);
604 Hexa_Traceback (Traceback, Suppress_Hex, Res);
606 Module_Symbolic_Traceback
613 end Symbolic_Traceback_No_Lock;
615 ------------------------
616 -- Symbolic_Traceback --
617 ------------------------
619 function Symbolic_Traceback
620 (Traceback : Tracebacks_Array;
621 Suppress_Hex : Boolean) return String
623 Res : Bounded_String (Max_Length => Max_String_Length);
625 System.Soft_Links.Lock_Task.all;
627 Symbolic_Traceback_No_Lock (Traceback, Suppress_Hex, Res);
628 System.Soft_Links.Unlock_Task.all;
630 return To_String (Res);
634 System.Soft_Links.Unlock_Task.all;
636 end Symbolic_Traceback;
638 function Symbolic_Traceback
639 (Traceback : System.Traceback_Entries.Tracebacks_Array) return String is
641 return Symbolic_Traceback (Traceback, Suppress_Hex => False);
642 end Symbolic_Traceback;
644 function Symbolic_Traceback_No_Hex
645 (Traceback : System.Traceback_Entries.Tracebacks_Array) return String is
647 return Symbolic_Traceback (Traceback, Suppress_Hex => True);
648 end Symbolic_Traceback_No_Hex;
650 function Symbolic_Traceback
651 (E : Ada.Exceptions.Exception_Occurrence;
652 Suppress_Hex : Boolean) return String
655 return Symbolic_Traceback
656 (Ada.Exceptions.Traceback.Tracebacks (E),
658 end Symbolic_Traceback;
660 function Symbolic_Traceback
661 (E : Ada.Exceptions.Exception_Occurrence) return String
664 return Symbolic_Traceback (E, Suppress_Hex => False);
665 end Symbolic_Traceback;
667 function Symbolic_Traceback_No_Hex
668 (E : Ada.Exceptions.Exception_Occurrence) return String is
670 return Symbolic_Traceback (E, Suppress_Hex => True);
671 end Symbolic_Traceback_No_Hex;
673 Exception_Tracebacks_Symbolic : Integer;
676 Exception_Tracebacks_Symbolic,
677 "__gl_exception_tracebacks_symbolic");
678 -- Boolean indicating whether symbolic tracebacks should be generated.
680 use Standard_Library;
682 -- If this version of this package is available, and the binder switch -Es
683 -- was given, then we want to use this as the decorator by default, and we
684 -- want to turn on tracing for Unhandled_Raise_In_Main. Note that the user
685 -- cannot have already set Exception_Trace, because the runtime library is
686 -- elaborated before user-defined code.
688 if Exception_Tracebacks_Symbolic /= 0 then
689 Exception_Traces.Set_Trace_Decorator (Symbolic_Traceback'Access);
690 pragma Assert (Exception_Trace = RM_Convention);
691 Exception_Trace := Unhandled_Raise_In_Main;
693 end System.Traceback.Symbolic;