gcc/ada/
[official-gcc.git] / gcc / ada / a-exexda.adb
blobec45c02e0355a3ccd83d363a7cee054a4fe9bea3
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- ADA.EXCEPTIONS.EXCEPTION_DATA --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2014, Free Software Foundation, Inc. --
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 ------------------------------------------------------------------------------
32 with System.Storage_Elements; use System.Storage_Elements;
34 separate (Ada.Exceptions)
35 package body Exception_Data is
37 -- This unit implements the Exception_Information related services for
38 -- both the Ada standard requirements and the GNAT.Exception_Traces
39 -- facility. This is also used by the implementation of the stream
40 -- attributes of types Exception_Id and Exception_Occurrence.
42 -- There are common parts between the contents of Exception_Information
43 -- (the regular Ada interface) and Untailored_Exception_Information (used
44 -- for streaming, and when there is no symbolic traceback available) The
45 -- overall structure is sketched below:
48 -- Untailored_Exception_Information
49 -- |
50 -- +-------+--------+
51 -- | |
52 -- Basic_Exc_Info & Untailored_Exc_Tback
53 -- (B_E_I) (U_E_TB)
55 -- o--
56 -- (B_E_I) | Exception_Name: <exception name> (as in Exception_Name)
57 -- | Message: <message> (or a null line if no message)
58 -- | PID=nnnn (if != 0)
59 -- o--
60 -- (U_E_TB) | Call stack traceback locations:
61 -- | <0xyyyyyyyy 0xyyyyyyyy ...>
62 -- o--
64 -- Exception_Information
65 -- |
66 -- +----------+----------+
67 -- | |
68 -- Basic_Exc_Info & traceback
69 -- |
70 -- +-----------+------------+
71 -- | |
72 -- Untailored_Exc_Tback Or Tback_Decorator
73 -- if no decorator set otherwise
75 -- Functions returning String imply secondary stack use, which is a heavy
76 -- mechanism requiring run-time support. Besides, some of the routines we
77 -- provide here are to be used by the default Last_Chance_Handler, at the
78 -- critical point where the runtime is about to be finalized. Since most
79 -- of the items we have at hand are of bounded length, we also provide a
80 -- procedural interface able to incrementally append the necessary bits to
81 -- a preallocated buffer or output them straight to stderr.
83 -- The procedural interface is composed of two major sections: a neutral
84 -- section for basic types like Address, Character, Natural or String, and
85 -- an exception oriented section for the exception names, messages, and
86 -- information. This is the Append_Info family of procedures below.
88 -- Output to stderr is commanded by passing an empty buffer to update, and
89 -- care is taken not to overflow otherwise.
91 --------------------------------------------
92 -- Procedural Interface - Neutral section --
93 --------------------------------------------
95 procedure Append_Info_Address
96 (A : Address;
97 Info : in out String;
98 Ptr : in out Natural);
100 procedure Append_Info_Character
101 (C : Character;
102 Info : in out String;
103 Ptr : in out Natural);
105 procedure Append_Info_Nat
106 (N : Natural;
107 Info : in out String;
108 Ptr : in out Natural);
110 procedure Append_Info_NL
111 (Info : in out String;
112 Ptr : in out Natural);
113 pragma Inline (Append_Info_NL);
115 procedure Append_Info_String
116 (S : String;
117 Info : in out String;
118 Ptr : in out Natural);
120 -------------------------------------------------------
121 -- Procedural Interface - Exception oriented section --
122 -------------------------------------------------------
124 procedure Append_Info_Exception_Name
125 (Id : Exception_Id;
126 Info : in out String;
127 Ptr : in out Natural);
129 procedure Append_Info_Exception_Name
130 (X : Exception_Occurrence;
131 Info : in out String;
132 Ptr : in out Natural);
134 procedure Append_Info_Exception_Message
135 (X : Exception_Occurrence;
136 Info : in out String;
137 Ptr : in out Natural);
139 procedure Append_Info_Basic_Exception_Information
140 (X : Exception_Occurrence;
141 Info : in out String;
142 Ptr : in out Natural);
144 procedure Append_Info_Untailored_Exception_Traceback
145 (X : Exception_Occurrence;
146 Info : in out String;
147 Ptr : in out Natural);
149 procedure Append_Info_Untailored_Exception_Information
150 (X : Exception_Occurrence;
151 Info : in out String;
152 Ptr : in out Natural);
154 -- The "functional" interface to the exception information not involving
155 -- a traceback decorator uses preallocated intermediate buffers to avoid
156 -- the use of secondary stack. Preallocation requires preliminary length
157 -- computation, for which a series of functions are introduced:
159 ---------------------------------
160 -- Length evaluation utilities --
161 ---------------------------------
163 function Basic_Exception_Info_Maxlength
164 (X : Exception_Occurrence) return Natural;
166 function Untailored_Exception_Traceback_Maxlength
167 (X : Exception_Occurrence) return Natural;
169 function Exception_Info_Maxlength
170 (X : Exception_Occurrence) return Natural;
172 function Exception_Name_Length
173 (Id : Exception_Id) return Natural;
175 function Exception_Name_Length
176 (X : Exception_Occurrence) return Natural;
178 function Exception_Message_Length
179 (X : Exception_Occurrence) return Natural;
181 --------------------------
182 -- Functional Interface --
183 --------------------------
185 function Untailored_Exception_Traceback
186 (X : Exception_Occurrence) return String;
187 -- Returns an image of the complete call chain associated with an
188 -- exception occurrence in its most basic form, that is as a raw sequence
189 -- of hexadecimal addresses.
191 function Tailored_Exception_Traceback
192 (X : Exception_Occurrence) return String;
193 -- Returns an image of the complete call chain associated with an
194 -- exception occurrence, either in its basic form if no decorator is
195 -- in place, or as formatted by the decorator otherwise.
197 -----------------------------------------------------------------------
198 -- Services for the default Last_Chance_Handler and the task wrapper --
199 -----------------------------------------------------------------------
201 pragma Export
202 (Ada, Append_Info_Exception_Message, "__gnat_append_info_e_msg");
204 pragma Export
205 (Ada, Append_Info_Untailored_Exception_Information,
206 "__gnat_append_info_u_e_info");
208 pragma Export
209 (Ada, Exception_Message_Length, "__gnat_exception_msg_len");
211 function Get_Executable_Load_Address return System.Address;
212 pragma Import (C, Get_Executable_Load_Address,
213 "__gnat_get_executable_load_address");
214 -- Get the load address of the executable, or Null_Address if not known
216 -------------------------
217 -- Append_Info_Address --
218 -------------------------
220 procedure Append_Info_Address
221 (A : Address;
222 Info : in out String;
223 Ptr : in out Natural)
225 S : String (1 .. 18);
226 P : Natural;
227 N : Integer_Address;
229 H : constant array (Integer range 0 .. 15) of Character :=
230 "0123456789abcdef";
231 begin
232 P := S'Last;
233 N := To_Integer (A);
234 loop
235 S (P) := H (Integer (N mod 16));
236 P := P - 1;
237 N := N / 16;
238 exit when N = 0;
239 end loop;
241 S (P - 1) := '0';
242 S (P) := 'x';
244 Append_Info_String (S (P - 1 .. S'Last), Info, Ptr);
245 end Append_Info_Address;
247 ---------------------------------------------
248 -- Append_Info_Basic_Exception_Information --
249 ---------------------------------------------
251 -- To ease the maximum length computation, we define and pull out a couple
252 -- of string constants:
254 BEI_Name_Header : constant String := "Exception name: ";
255 BEI_Msg_Header : constant String := "Message: ";
256 BEI_PID_Header : constant String := "PID: ";
258 procedure Append_Info_Basic_Exception_Information
259 (X : Exception_Occurrence;
260 Info : in out String;
261 Ptr : in out Natural)
263 Name : String (1 .. Exception_Name_Length (X));
264 -- Buffer in which to fetch the exception name, in order to check
265 -- whether this is an internal _ABORT_SIGNAL or a regular occurrence.
267 Name_Ptr : Natural := Name'First - 1;
269 begin
270 -- Output exception name and message except for _ABORT_SIGNAL, where
271 -- these two lines are omitted.
273 Append_Info_Exception_Name (X, Name, Name_Ptr);
275 if Name (Name'First) /= '_' then
276 Append_Info_String (BEI_Name_Header, Info, Ptr);
277 Append_Info_String (Name, Info, Ptr);
278 Append_Info_NL (Info, Ptr);
280 if Exception_Message_Length (X) /= 0 then
281 Append_Info_String (BEI_Msg_Header, Info, Ptr);
282 Append_Info_Exception_Message (X, Info, Ptr);
283 Append_Info_NL (Info, Ptr);
284 end if;
285 end if;
287 -- Output PID line if non-zero
289 if X.Pid /= 0 then
290 Append_Info_String (BEI_PID_Header, Info, Ptr);
291 Append_Info_Nat (X.Pid, Info, Ptr);
292 Append_Info_NL (Info, Ptr);
293 end if;
294 end Append_Info_Basic_Exception_Information;
296 ---------------------------
297 -- Append_Info_Character --
298 ---------------------------
300 procedure Append_Info_Character
301 (C : Character;
302 Info : in out String;
303 Ptr : in out Natural)
305 begin
306 if Info'Length = 0 then
307 To_Stderr (C);
308 elsif Ptr < Info'Last then
309 Ptr := Ptr + 1;
310 Info (Ptr) := C;
311 end if;
312 end Append_Info_Character;
314 -----------------------------------
315 -- Append_Info_Exception_Message --
316 -----------------------------------
318 procedure Append_Info_Exception_Message
319 (X : Exception_Occurrence;
320 Info : in out String;
321 Ptr : in out Natural)
323 begin
324 if X.Id = Null_Id then
325 raise Constraint_Error;
326 end if;
328 declare
329 Len : constant Natural := Exception_Message_Length (X);
330 Msg : constant String (1 .. Len) := X.Msg (1 .. Len);
331 begin
332 Append_Info_String (Msg, Info, Ptr);
333 end;
334 end Append_Info_Exception_Message;
336 --------------------------------
337 -- Append_Info_Exception_Name --
338 --------------------------------
340 procedure Append_Info_Exception_Name
341 (Id : Exception_Id;
342 Info : in out String;
343 Ptr : in out Natural)
345 begin
346 if Id = Null_Id then
347 raise Constraint_Error;
348 end if;
350 declare
351 Len : constant Natural := Exception_Name_Length (Id);
352 Name : constant String (1 .. Len) := To_Ptr (Id.Full_Name) (1 .. Len);
353 begin
354 Append_Info_String (Name, Info, Ptr);
355 end;
356 end Append_Info_Exception_Name;
358 procedure Append_Info_Exception_Name
359 (X : Exception_Occurrence;
360 Info : in out String;
361 Ptr : in out Natural)
363 begin
364 Append_Info_Exception_Name (X.Id, Info, Ptr);
365 end Append_Info_Exception_Name;
367 ------------------------------
368 -- Exception_Info_Maxlength --
369 ------------------------------
371 function Exception_Info_Maxlength
372 (X : Exception_Occurrence) return Natural
374 begin
375 return
376 Basic_Exception_Info_Maxlength (X)
377 + Untailored_Exception_Traceback_Maxlength (X);
378 end Exception_Info_Maxlength;
380 ---------------------
381 -- Append_Info_Nat --
382 ---------------------
384 procedure Append_Info_Nat
385 (N : Natural;
386 Info : in out String;
387 Ptr : in out Natural)
389 begin
390 if N > 9 then
391 Append_Info_Nat (N / 10, Info, Ptr);
392 end if;
394 Append_Info_Character
395 (Character'Val (Character'Pos ('0') + N mod 10), Info, Ptr);
396 end Append_Info_Nat;
398 --------------------
399 -- Append_Info_NL --
400 --------------------
402 procedure Append_Info_NL
403 (Info : in out String;
404 Ptr : in out Natural)
406 begin
407 Append_Info_Character (ASCII.LF, Info, Ptr);
408 end Append_Info_NL;
410 ------------------------
411 -- Append_Info_String --
412 ------------------------
414 procedure Append_Info_String
415 (S : String;
416 Info : in out String;
417 Ptr : in out Natural)
419 begin
420 if Info'Length = 0 then
421 To_Stderr (S);
422 else
423 declare
424 Last : constant Natural :=
425 Integer'Min (Ptr + S'Length, Info'Last);
426 begin
427 Info (Ptr + 1 .. Last) := S;
428 Ptr := Last;
429 end;
430 end if;
431 end Append_Info_String;
433 --------------------------------------------------
434 -- Append_Info_Untailored_Exception_Information --
435 --------------------------------------------------
437 procedure Append_Info_Untailored_Exception_Information
438 (X : Exception_Occurrence;
439 Info : in out String;
440 Ptr : in out Natural)
442 begin
443 Append_Info_Basic_Exception_Information (X, Info, Ptr);
444 Append_Info_Untailored_Exception_Traceback (X, Info, Ptr);
445 end Append_Info_Untailored_Exception_Information;
447 ------------------------------------------------
448 -- Append_Info_Untailored_Exception_Traceback --
449 ------------------------------------------------
451 -- As for Basic_Exception_Information:
453 BETB_Header : constant String := "Call stack traceback locations:";
454 LDAD_Header : constant String := "Load address: ";
456 procedure Append_Info_Untailored_Exception_Traceback
457 (X : Exception_Occurrence;
458 Info : in out String;
459 Ptr : in out Natural)
461 Load_Address : Address;
463 begin
464 if X.Num_Tracebacks = 0 then
465 return;
466 end if;
468 -- The executable load address line
470 Load_Address := Get_Executable_Load_Address;
472 if Load_Address /= Null_Address then
473 Append_Info_String (LDAD_Header, Info, Ptr);
474 Append_Info_Address (Load_Address, Info, Ptr);
475 Append_Info_NL (Info, Ptr);
476 end if;
478 -- The traceback lines
480 Append_Info_String (BETB_Header, Info, Ptr);
481 Append_Info_NL (Info, Ptr);
483 for J in 1 .. X.Num_Tracebacks loop
484 Append_Info_Address (TBE.PC_For (X.Tracebacks (J)), Info, Ptr);
485 exit when J = X.Num_Tracebacks;
486 Append_Info_Character (' ', Info, Ptr);
487 end loop;
489 Append_Info_NL (Info, Ptr);
490 end Append_Info_Untailored_Exception_Traceback;
492 -------------------------------------------
493 -- Basic_Exception_Information_Maxlength --
494 -------------------------------------------
496 function Basic_Exception_Info_Maxlength
497 (X : Exception_Occurrence) return Natural
499 begin
500 return
501 BEI_Name_Header'Length + Exception_Name_Length (X) + 1
502 + BEI_Msg_Header'Length + Exception_Message_Length (X) + 1
503 + BEI_PID_Header'Length + 15;
504 end Basic_Exception_Info_Maxlength;
506 ---------------------------
507 -- Exception_Information --
508 ---------------------------
510 function Exception_Information (X : Exception_Occurrence) return String is
511 -- The tailored exception information is the basic information
512 -- associated with the tailored call chain backtrace.
514 Tback_Info : constant String := Tailored_Exception_Traceback (X);
515 Tback_Len : constant Natural := Tback_Info'Length;
517 Info : String (1 .. Basic_Exception_Info_Maxlength (X) + Tback_Len);
518 Ptr : Natural := Info'First - 1;
520 begin
521 Append_Info_Basic_Exception_Information (X, Info, Ptr);
522 Append_Info_String (Tback_Info, Info, Ptr);
523 return Info (Info'First .. Ptr);
524 end Exception_Information;
526 ------------------------------
527 -- Exception_Message_Length --
528 ------------------------------
530 function Exception_Message_Length
531 (X : Exception_Occurrence) return Natural
533 begin
534 return X.Msg_Length;
535 end Exception_Message_Length;
537 ---------------------------
538 -- Exception_Name_Length --
539 ---------------------------
541 function Exception_Name_Length (Id : Exception_Id) return Natural is
542 begin
543 -- What is stored in the internal Name buffer includes a terminating
544 -- null character that we never care about.
546 return Id.Name_Length - 1;
547 end Exception_Name_Length;
549 function Exception_Name_Length (X : Exception_Occurrence) return Natural is
550 begin
551 return Exception_Name_Length (X.Id);
552 end Exception_Name_Length;
554 -------------------------------
555 -- Untailored_Exception_Traceback --
556 -------------------------------
558 function Untailored_Exception_Traceback
559 (X : Exception_Occurrence) return String
561 Info : aliased String
562 (1 .. Untailored_Exception_Traceback_Maxlength (X));
563 Ptr : Natural := Info'First - 1;
564 begin
565 Append_Info_Untailored_Exception_Traceback (X, Info, Ptr);
566 return Info (Info'First .. Ptr);
567 end Untailored_Exception_Traceback;
569 --------------------------------------
570 -- Untailored_Exception_Information --
571 --------------------------------------
573 function Untailored_Exception_Information
574 (X : Exception_Occurrence) return String
576 Info : String (1 .. Exception_Info_Maxlength (X));
577 Ptr : Natural := Info'First - 1;
578 begin
579 Append_Info_Untailored_Exception_Information (X, Info, Ptr);
580 return Info (Info'First .. Ptr);
581 end Untailored_Exception_Information;
583 -------------------------
584 -- Set_Exception_C_Msg --
585 -------------------------
587 procedure Set_Exception_C_Msg
588 (Excep : EOA;
589 Id : Exception_Id;
590 Msg1 : System.Address;
591 Line : Integer := 0;
592 Column : Integer := 0;
593 Msg2 : System.Address := System.Null_Address)
595 Remind : Integer;
596 Ptr : Natural;
598 procedure Append_Number (Number : Integer);
599 -- Append given number to Excep.Msg
601 -------------------
602 -- Append_Number --
603 -------------------
605 procedure Append_Number (Number : Integer) is
606 Val : Integer;
607 Size : Integer;
609 begin
610 if Number <= 0 then
611 return;
612 end if;
614 -- Compute the number of needed characters
616 Size := 1;
617 Val := Number;
618 while Val > 0 loop
619 Val := Val / 10;
620 Size := Size + 1;
621 end loop;
623 -- If enough characters are available, put the line number
625 if Excep.Msg_Length <= Exception_Msg_Max_Length - Size then
626 Excep.Msg (Excep.Msg_Length + 1) := ':';
627 Excep.Msg_Length := Excep.Msg_Length + Size;
629 Val := Number;
630 Size := 0;
631 while Val > 0 loop
632 Remind := Val rem 10;
633 Val := Val / 10;
634 Excep.Msg (Excep.Msg_Length - Size) :=
635 Character'Val (Remind + Character'Pos ('0'));
636 Size := Size + 1;
637 end loop;
638 end if;
639 end Append_Number;
641 -- Start of processing for Set_Exception_C_Msg
643 begin
644 Excep.Exception_Raised := False;
645 Excep.Id := Id;
646 Excep.Num_Tracebacks := 0;
647 Excep.Pid := Local_Partition_ID;
648 Excep.Msg_Length := 0;
650 while To_Ptr (Msg1) (Excep.Msg_Length + 1) /= ASCII.NUL
651 and then Excep.Msg_Length < Exception_Msg_Max_Length
652 loop
653 Excep.Msg_Length := Excep.Msg_Length + 1;
654 Excep.Msg (Excep.Msg_Length) := To_Ptr (Msg1) (Excep.Msg_Length);
655 end loop;
657 Append_Number (Line);
658 Append_Number (Column);
660 -- Append second message if present
662 if Msg2 /= System.Null_Address
663 and then Excep.Msg_Length + 1 < Exception_Msg_Max_Length
664 then
665 Excep.Msg_Length := Excep.Msg_Length + 1;
666 Excep.Msg (Excep.Msg_Length) := ' ';
668 Ptr := 1;
669 while To_Ptr (Msg2) (Ptr) /= ASCII.NUL
670 and then Excep.Msg_Length < Exception_Msg_Max_Length
671 loop
672 Excep.Msg_Length := Excep.Msg_Length + 1;
673 Excep.Msg (Excep.Msg_Length) := To_Ptr (Msg2) (Ptr);
674 Ptr := Ptr + 1;
675 end loop;
676 end if;
677 end Set_Exception_C_Msg;
679 -----------------------
680 -- Set_Exception_Msg --
681 -----------------------
683 procedure Set_Exception_Msg
684 (Excep : EOA;
685 Id : Exception_Id;
686 Message : String)
688 Len : constant Natural :=
689 Natural'Min (Message'Length, Exception_Msg_Max_Length);
690 First : constant Integer := Message'First;
691 begin
692 Excep.Exception_Raised := False;
693 Excep.Msg_Length := Len;
694 Excep.Msg (1 .. Len) := Message (First .. First + Len - 1);
695 Excep.Id := Id;
696 Excep.Num_Tracebacks := 0;
697 Excep.Pid := Local_Partition_ID;
698 end Set_Exception_Msg;
700 ----------------------------------
701 -- Tailored_Exception_Traceback --
702 ----------------------------------
704 function Tailored_Exception_Traceback
705 (X : Exception_Occurrence) return String
707 -- We reference the decorator *wrapper* here and not the decorator
708 -- itself. The purpose of the local variable Wrapper is to prevent a
709 -- potential race condition in the code below. The atomicity of this
710 -- assignment is enforced by pragma Atomic in System.Soft_Links.
712 -- The potential race condition here, if no local variable was used,
713 -- relates to the test upon the wrapper's value and the call, which
714 -- are not performed atomically. With the local variable, potential
715 -- changes of the wrapper's global value between the test and the
716 -- call become inoffensive.
718 Wrapper : constant Traceback_Decorator_Wrapper_Call :=
719 Traceback_Decorator_Wrapper;
721 begin
722 if Wrapper = null then
723 return Untailored_Exception_Traceback (X);
724 else
725 return Wrapper.all (X.Tracebacks'Address, X.Num_Tracebacks);
726 end if;
727 end Tailored_Exception_Traceback;
729 ----------------------------------------------
730 -- Untailored_Exception_Traceback_Maxlength --
731 ----------------------------------------------
733 function Untailored_Exception_Traceback_Maxlength
734 (X : Exception_Occurrence) return Natural
736 Space_Per_Address : constant := 2 + 16 + 1;
737 -- Space for "0x" + HHHHHHHHHHHHHHHH + " "
738 begin
739 return
740 LDAD_Header'Length + Space_Per_Address + BETB_Header'Length + 1 +
741 X.Num_Tracebacks * Space_Per_Address + 1;
742 end Untailored_Exception_Traceback_Maxlength;
744 end Exception_Data;