comparison gcc/ada/libgnat/s-trasym__dwarf.adb @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
comparison
equal deleted inserted replaced
68:561a7518be6b 111:04ced10e8804
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- S Y S T E M . T R A C E B A C K . S Y M B O L I C --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1999-2017, AdaCore --
10 -- --
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. --
17 -- --
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. --
21 -- --
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/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
31
32 -- Run-time symbolic traceback support for targets using DWARF debug data
33
34 pragma Polling (Off);
35 -- We must turn polling off for this unit, because otherwise we can get
36 -- elaboration circularities when polling is turned on.
37
38 with Ada.Unchecked_Deallocation;
39
40 with Ada.Exceptions.Traceback; use Ada.Exceptions.Traceback;
41 with Ada.Containers.Generic_Array_Sort;
42
43 with System.Address_To_Access_Conversions;
44 with System.Soft_Links;
45 with System.CRTL;
46 with System.Dwarf_Lines;
47 with System.Exception_Traces;
48 with System.Standard_Library;
49 with System.Traceback_Entries;
50 with System.Strings;
51 with System.Bounded_Strings;
52
53 package body System.Traceback.Symbolic is
54
55 use System.Bounded_Strings;
56 use System.Dwarf_Lines;
57
58 subtype Big_String is String (Positive);
59 -- To deal with C strings
60
61 package Big_String_Conv is new System.Address_To_Access_Conversions
62 (Big_String);
63
64 type Module_Cache;
65 type Module_Cache_Acc is access all Module_Cache;
66
67 type Module_Cache is record
68 Name : Strings.String_Access;
69 -- Name of the module
70
71 C : Dwarf_Context (In_Exception => True);
72 -- Context to symbolize an address within this module
73
74 Chain : Module_Cache_Acc;
75 end record;
76
77 procedure Free is new Ada.Unchecked_Deallocation
78 (Module_Cache,
79 Module_Cache_Acc);
80
81 Cache_Chain : Module_Cache_Acc;
82 -- Simply linked list of modules
83
84 type Module_Array is array (Natural range <>) of Module_Cache_Acc;
85 type Module_Array_Acc is access Module_Array;
86
87 Modules_Cache : Module_Array_Acc;
88 -- Sorted array of cached modules (if not null)
89
90 Exec_Module : aliased Module_Cache;
91 -- Context for the executable
92
93 type Init_State is (Uninitialized, Initialized, Failed);
94 Exec_Module_State : Init_State := Uninitialized;
95 -- How Exec_Module is initialized
96
97 procedure Init_Exec_Module;
98 -- Initialize Exec_Module if not already initialized
99
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.
108
109 function Lt (Left, Right : Module_Cache_Acc) return Boolean;
110 -- Sort function for Module_Cache
111
112 procedure Init_Module
113 (Module : out Module_Cache;
114 Success : out Boolean;
115 Module_Name : String;
116 Load_Address : Address := Null_Address);
117 -- Initialize Module
118
119 procedure Close_Module (Module : in out Module_Cache);
120 -- Finalize Module
121
122 function Value (Item : System.Address) return String;
123 -- Return the String contained in Item, up until the first NUL character
124
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.
129
130 package Module_Name is
131
132 procedure Build_Cache_For_All_Modules;
133 -- Create the cache for all current modules
134
135 function Get (Addr : access System.Address) return String;
136 -- Returns the module name for the given address, Addr may be updated
137 -- to be set relative to a shared library. This depends on the platform.
138 -- Returns an empty string for the main executable.
139
140 function Is_Supported return Boolean;
141 pragma Inline (Is_Supported);
142 -- Returns True if Module_Name is supported, so if the traceback is
143 -- supported for shared libraries.
144
145 end Module_Name;
146
147 package body Module_Name is separate;
148
149 function Executable_Name return String;
150 -- Returns the executable name as reported by argv[0]. If gnat_argv not
151 -- initialized or if argv[0] executable not found in path, function returns
152 -- an empty string.
153
154 function Get_Executable_Load_Address return System.Address;
155 pragma Import
156 (C,
157 Get_Executable_Load_Address,
158 "__gnat_get_executable_load_address");
159 -- Get the load address of the executable, or Null_Address if not known
160
161 procedure Hexa_Traceback
162 (Traceback : Tracebacks_Array;
163 Suppress_Hex : Boolean;
164 Res : in out Bounded_String);
165 -- Non-symbolic traceback (simply write addresses in hexa)
166
167 procedure Symbolic_Traceback_No_Lock
168 (Traceback : Tracebacks_Array;
169 Suppress_Hex : Boolean;
170 Res : in out Bounded_String);
171 -- Like the public Symbolic_Traceback_No_Lock except there is no provision
172 -- against concurrent accesses.
173
174 procedure Module_Symbolic_Traceback
175 (Traceback : Tracebacks_Array;
176 Module : Module_Cache;
177 Suppress_Hex : Boolean;
178 Res : in out Bounded_String);
179 -- Returns the Traceback for a given module
180
181 procedure Multi_Module_Symbolic_Traceback
182 (Traceback : Tracebacks_Array;
183 Suppress_Hex : Boolean;
184 Res : in out Bounded_String);
185 -- Build string containing symbolic traceback for the given call chain
186
187 procedure Multi_Module_Symbolic_Traceback
188 (Traceback : Tracebacks_Array;
189 Module : Module_Cache;
190 Suppress_Hex : Boolean;
191 Res : in out Bounded_String);
192 -- Likewise but using Module
193
194 Max_String_Length : constant := 4096;
195 -- Arbitrary limit on Bounded_Str length
196
197 -----------
198 -- Value --
199 -----------
200
201 function Value (Item : System.Address) return String is
202 begin
203 if Item /= Null_Address then
204 for J in Big_String'Range loop
205 if Big_String_Conv.To_Pointer (Item) (J) = ASCII.NUL then
206 return Big_String_Conv.To_Pointer (Item) (1 .. J - 1);
207 end if;
208 end loop;
209 end if;
210
211 return "";
212 end Value;
213
214 -------------------------
215 -- Add_Module_To_Cache --
216 -------------------------
217
218 procedure Add_Module_To_Cache (Module_Name : String) is
219 Module : Module_Cache_Acc;
220 Success : Boolean;
221 begin
222 Module := new Module_Cache;
223 Init_Module (Module.all, Success, Module_Name);
224 if not Success then
225 Free (Module);
226 return;
227 end if;
228 Module.Chain := Cache_Chain;
229 Cache_Chain := Module;
230 end Add_Module_To_Cache;
231
232 ----------------------
233 -- Init_Exec_Module --
234 ----------------------
235
236 procedure Init_Exec_Module is
237 begin
238 if Exec_Module_State = Uninitialized then
239 declare
240 Exec_Path : constant String := Executable_Name;
241 Exec_Load : constant Address := Get_Executable_Load_Address;
242 Success : Boolean;
243 begin
244 Init_Module (Exec_Module, Success, Exec_Path, Exec_Load);
245
246 if Success then
247 Exec_Module_State := Initialized;
248 else
249 Exec_Module_State := Failed;
250 end if;
251 end;
252 end if;
253 end Init_Exec_Module;
254
255 --------
256 -- Lt --
257 --------
258
259 function Lt (Left, Right : Module_Cache_Acc) return Boolean is
260 begin
261 return Low (Left.C) < Low (Right.C);
262 end Lt;
263
264 -----------------------------
265 -- Module_Cache_Array_Sort --
266 -----------------------------
267
268 procedure Module_Cache_Array_Sort is new Ada.Containers.Generic_Array_Sort
269 (Natural,
270 Module_Cache_Acc,
271 Module_Array,
272 Lt);
273
274 ------------------
275 -- Enable_Cache --
276 ------------------
277
278 procedure Enable_Cache (Include_Modules : Boolean := False) is
279 begin
280 -- Can be called at most once
281 if Cache_Chain /= null then
282 return;
283 end if;
284
285 -- Add all modules
286 Init_Exec_Module;
287 Cache_Chain := Exec_Module'Access;
288
289 if Include_Modules then
290 Module_Name.Build_Cache_For_All_Modules;
291 end if;
292
293 -- Build and fill the array of modules
294 declare
295 Count : Natural;
296 Module : Module_Cache_Acc;
297 begin
298 for Phase in 1 .. 2 loop
299 Count := 0;
300 Module := Cache_Chain;
301 while Module /= null loop
302 Count := Count + 1;
303
304 if Phase = 1 then
305 Enable_Cache (Module.C);
306 else
307 Modules_Cache (Count) := Module;
308 end if;
309 Module := Module.Chain;
310 end loop;
311
312 if Phase = 1 then
313 Modules_Cache := new Module_Array (1 .. Count);
314 end if;
315 end loop;
316 end;
317
318 -- Sort the array
319 Module_Cache_Array_Sort (Modules_Cache.all);
320 end Enable_Cache;
321
322 ---------------------
323 -- Executable_Name --
324 ---------------------
325
326 function Executable_Name return String is
327 -- We have to import gnat_argv as an Address to match the type of
328 -- gnat_argv in the binder generated file. Otherwise, we get spurious
329 -- warnings about type mismatch when LTO is turned on.
330
331 Gnat_Argv : System.Address;
332 pragma Import (C, Gnat_Argv, "gnat_argv");
333
334 type Argv_Array is array (0 .. 0) of System.Address;
335 package Conv is new System.Address_To_Access_Conversions (Argv_Array);
336
337 function locate_exec_on_path (A : System.Address) return System.Address;
338 pragma Import (C, locate_exec_on_path, "__gnat_locate_exec_on_path");
339
340 begin
341 if Gnat_Argv = Null_Address then
342 return "";
343 end if;
344
345 declare
346 Addr : constant System.Address :=
347 locate_exec_on_path (Conv.To_Pointer (Gnat_Argv) (0));
348 Result : constant String := Value (Addr);
349
350 begin
351 -- The buffer returned by locate_exec_on_path was allocated using
352 -- malloc, so we should use free to release the memory.
353
354 if Addr /= Null_Address then
355 System.CRTL.free (Addr);
356 end if;
357
358 return Result;
359 end;
360 end Executable_Name;
361
362 ------------------
363 -- Close_Module --
364 ------------------
365
366 procedure Close_Module (Module : in out Module_Cache) is
367 begin
368 Close (Module.C);
369 Strings.Free (Module.Name);
370 end Close_Module;
371
372 -----------------
373 -- Init_Module --
374 -----------------
375
376 procedure Init_Module
377 (Module : out Module_Cache;
378 Success : out Boolean;
379 Module_Name : String;
380 Load_Address : Address := Null_Address)
381 is
382 begin
383 -- Early return if the module is not known
384
385 if Module_Name = "" then
386 Success := False;
387 return;
388 end if;
389
390 Open (Module_Name, Module.C, Success);
391
392 -- If a module can't be opened just return now, we just cannot give more
393 -- information in this case.
394
395 if not Success then
396 return;
397 end if;
398
399 Set_Load_Address (Module.C, Load_Address);
400
401 Module.Name := new String'(Module_Name);
402 end Init_Module;
403
404 -------------------------------
405 -- Module_Symbolic_Traceback --
406 -------------------------------
407
408 procedure Module_Symbolic_Traceback
409 (Traceback : Tracebacks_Array;
410 Module : Module_Cache;
411 Suppress_Hex : Boolean;
412 Res : in out Bounded_String)
413 is
414 Success : Boolean := False;
415 begin
416 if Symbolic.Module_Name.Is_Supported then
417 Append (Res, '[');
418 Append (Res, Module.Name.all);
419 Append (Res, ']' & ASCII.LF);
420 end if;
421
422 Dwarf_Lines.Symbolic_Traceback
423 (Module.C,
424 Traceback,
425 Suppress_Hex,
426 Success,
427 Res);
428
429 if not Success then
430 Hexa_Traceback (Traceback, Suppress_Hex, Res);
431 end if;
432
433 -- We must not allow an unhandled exception here, since this function
434 -- may be installed as a decorator for all automatic exceptions.
435
436 exception
437 when others =>
438 return;
439 end Module_Symbolic_Traceback;
440
441 -------------------------------------
442 -- Multi_Module_Symbolic_Traceback --
443 -------------------------------------
444
445 procedure Multi_Module_Symbolic_Traceback
446 (Traceback : Tracebacks_Array;
447 Suppress_Hex : Boolean;
448 Res : in out Bounded_String)
449 is
450 F : constant Natural := Traceback'First;
451 begin
452 if Traceback'Length = 0 or else Is_Full (Res) then
453 return;
454 end if;
455
456 if Modules_Cache /= null then
457 -- Search in the cache
458
459 declare
460 Addr : constant Address := Traceback (F);
461 Hi, Lo, Mid : Natural;
462 begin
463 Lo := Modules_Cache'First;
464 Hi := Modules_Cache'Last;
465 while Lo <= Hi loop
466 Mid := (Lo + Hi) / 2;
467 if Addr < Low (Modules_Cache (Mid).C) then
468 Hi := Mid - 1;
469 elsif Is_Inside (Modules_Cache (Mid).C, Addr) then
470 Multi_Module_Symbolic_Traceback
471 (Traceback,
472 Modules_Cache (Mid).all,
473 Suppress_Hex,
474 Res);
475 return;
476 else
477 Lo := Mid + 1;
478 end if;
479 end loop;
480
481 -- Not found
482 Hexa_Traceback (Traceback (F .. F), Suppress_Hex, Res);
483 Multi_Module_Symbolic_Traceback
484 (Traceback (F + 1 .. Traceback'Last),
485 Suppress_Hex,
486 Res);
487 end;
488 else
489
490 -- First try the executable
491 if Is_Inside (Exec_Module.C, Traceback (F)) then
492 Multi_Module_Symbolic_Traceback
493 (Traceback,
494 Exec_Module,
495 Suppress_Hex,
496 Res);
497 return;
498 end if;
499
500 -- Otherwise, try a shared library
501 declare
502 Addr : aliased System.Address := Traceback (F);
503 M_Name : constant String := Module_Name.Get (Addr'Access);
504 Module : Module_Cache;
505 Success : Boolean;
506 begin
507 Init_Module (Module, Success, M_Name, System.Null_Address);
508 if Success then
509 Multi_Module_Symbolic_Traceback
510 (Traceback,
511 Module,
512 Suppress_Hex,
513 Res);
514 Close_Module (Module);
515 else
516 -- Module not found
517 Hexa_Traceback (Traceback (F .. F), Suppress_Hex, Res);
518 Multi_Module_Symbolic_Traceback
519 (Traceback (F + 1 .. Traceback'Last),
520 Suppress_Hex,
521 Res);
522 end if;
523 end;
524 end if;
525 end Multi_Module_Symbolic_Traceback;
526
527 procedure Multi_Module_Symbolic_Traceback
528 (Traceback : Tracebacks_Array;
529 Module : Module_Cache;
530 Suppress_Hex : Boolean;
531 Res : in out Bounded_String)
532 is
533 Pos : Positive;
534 begin
535 -- Will symbolize the first address...
536
537 Pos := Traceback'First + 1;
538
539 -- ... and all addresses in the same module
540
541 Same_Module :
542 loop
543 exit Same_Module when Pos > Traceback'Last;
544
545 -- Get address to check for corresponding module name
546
547 exit Same_Module when not Is_Inside (Module.C, Traceback (Pos));
548
549 Pos := Pos + 1;
550 end loop Same_Module;
551
552 Module_Symbolic_Traceback
553 (Traceback (Traceback'First .. Pos - 1),
554 Module,
555 Suppress_Hex,
556 Res);
557 Multi_Module_Symbolic_Traceback
558 (Traceback (Pos .. Traceback'Last),
559 Suppress_Hex,
560 Res);
561 end Multi_Module_Symbolic_Traceback;
562
563 --------------------
564 -- Hexa_Traceback --
565 --------------------
566
567 procedure Hexa_Traceback
568 (Traceback : Tracebacks_Array;
569 Suppress_Hex : Boolean;
570 Res : in out Bounded_String)
571 is
572 use System.Traceback_Entries;
573 begin
574 if Suppress_Hex then
575 Append (Res, "...");
576 Append (Res, ASCII.LF);
577 else
578 for J in Traceback'Range loop
579 Append_Address (Res, PC_For (Traceback (J)));
580 Append (Res, ASCII.LF);
581 end loop;
582 end if;
583 end Hexa_Traceback;
584
585 --------------------------------
586 -- Symbolic_Traceback_No_Lock --
587 --------------------------------
588
589 procedure Symbolic_Traceback_No_Lock
590 (Traceback : Tracebacks_Array;
591 Suppress_Hex : Boolean;
592 Res : in out Bounded_String)
593 is
594 begin
595 if Symbolic.Module_Name.Is_Supported then
596 Multi_Module_Symbolic_Traceback (Traceback, Suppress_Hex, Res);
597 else
598 if Exec_Module_State = Failed then
599 Append (Res, "Call stack traceback locations:" & ASCII.LF);
600 Hexa_Traceback (Traceback, Suppress_Hex, Res);
601 else
602 Module_Symbolic_Traceback
603 (Traceback,
604 Exec_Module,
605 Suppress_Hex,
606 Res);
607 end if;
608 end if;
609 end Symbolic_Traceback_No_Lock;
610
611 ------------------------
612 -- Symbolic_Traceback --
613 ------------------------
614
615 function Symbolic_Traceback
616 (Traceback : Tracebacks_Array;
617 Suppress_Hex : Boolean) return String
618 is
619 Res : Bounded_String (Max_Length => Max_String_Length);
620 begin
621 System.Soft_Links.Lock_Task.all;
622 Init_Exec_Module;
623 Symbolic_Traceback_No_Lock (Traceback, Suppress_Hex, Res);
624 System.Soft_Links.Unlock_Task.all;
625
626 return To_String (Res);
627
628 exception
629 when others =>
630 System.Soft_Links.Unlock_Task.all;
631 raise;
632 end Symbolic_Traceback;
633
634 function Symbolic_Traceback
635 (Traceback : System.Traceback_Entries.Tracebacks_Array) return String is
636 begin
637 return Symbolic_Traceback (Traceback, Suppress_Hex => False);
638 end Symbolic_Traceback;
639
640 function Symbolic_Traceback_No_Hex
641 (Traceback : System.Traceback_Entries.Tracebacks_Array) return String is
642 begin
643 return Symbolic_Traceback (Traceback, Suppress_Hex => True);
644 end Symbolic_Traceback_No_Hex;
645
646 function Symbolic_Traceback
647 (E : Ada.Exceptions.Exception_Occurrence;
648 Suppress_Hex : Boolean) return String
649 is
650 begin
651 return Symbolic_Traceback
652 (Ada.Exceptions.Traceback.Tracebacks (E),
653 Suppress_Hex);
654 end Symbolic_Traceback;
655
656 function Symbolic_Traceback
657 (E : Ada.Exceptions.Exception_Occurrence) return String
658 is
659 begin
660 return Symbolic_Traceback (E, Suppress_Hex => False);
661 end Symbolic_Traceback;
662
663 function Symbolic_Traceback_No_Hex
664 (E : Ada.Exceptions.Exception_Occurrence) return String is
665 begin
666 return Symbolic_Traceback (E, Suppress_Hex => True);
667 end Symbolic_Traceback_No_Hex;
668
669 Exception_Tracebacks_Symbolic : Integer;
670 pragma Import
671 (C,
672 Exception_Tracebacks_Symbolic,
673 "__gl_exception_tracebacks_symbolic");
674 -- Boolean indicating whether symbolic tracebacks should be generated.
675
676 use Standard_Library;
677 begin
678 -- If this version of this package is available, and the binder switch -Es
679 -- was given, then we want to use this as the decorator by default, and we
680 -- want to turn on tracing for Unhandled_Raise_In_Main. Note that the user
681 -- cannot have already set Exception_Trace, because the runtime library is
682 -- elaborated before user-defined code.
683
684 if Exception_Tracebacks_Symbolic /= 0 then
685 Exception_Traces.Set_Trace_Decorator (Symbolic_Traceback'Access);
686 pragma Assert (Exception_Trace = RM_Convention);
687 Exception_Trace := Unhandled_Raise_In_Main;
688 end if;
689 end System.Traceback.Symbolic;