1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- ADA.EXCEPTIONS.EXCEPTION_DATA --
9 -- Copyright (C) 1992-2014, Free Software Foundation, Inc. --
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 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
52 -- Basic_Exc_Info & Untailored_Exc_Tback
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)
60 -- (U_E_TB) | Call stack traceback locations:
61 -- | <0xyyyyyyyy 0xyyyyyyyy ...>
64 -- Exception_Information
66 -- +----------+----------+
68 -- Basic_Exc_Info & traceback
70 -- +-----------+------------+
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
98 Ptr
: in out Natural);
100 procedure Append_Info_Character
102 Info
: in out String;
103 Ptr
: in out Natural);
105 procedure Append_Info_Nat
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
117 Info
: in out String;
118 Ptr
: in out Natural);
120 -------------------------------------------------------
121 -- Procedural Interface - Exception oriented section --
122 -------------------------------------------------------
124 procedure Append_Info_Exception_Name
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 -----------------------------------------------------------------------
202 (Ada
, Append_Info_Exception_Message
, "__gnat_append_info_e_msg");
205 (Ada
, Append_Info_Untailored_Exception_Information
,
206 "__gnat_append_info_u_e_info");
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
222 Info
: in out String;
223 Ptr
: in out Natural)
225 S
: String (1 .. 18);
229 H
: constant array (Integer range 0 .. 15) of Character :=
235 S
(P
) := H
(Integer (N
mod 16));
244 Append_Info_String
(S
(P
- 1 .. S
'Last), Info
, Ptr
);
245 end Append_Info_Address
;
247 ---------------------------
248 -- Append_Info_Character --
249 ---------------------------
251 procedure Append_Info_Character
253 Info
: in out String;
254 Ptr
: in out Natural)
257 if Info
'Length = 0 then
259 elsif Ptr
< Info
'Last then
263 end Append_Info_Character
;
265 ---------------------
266 -- Append_Info_Nat --
267 ---------------------
269 procedure Append_Info_Nat
271 Info
: in out String;
272 Ptr
: in out Natural)
276 Append_Info_Nat
(N
/ 10, Info
, Ptr
);
279 Append_Info_Character
280 (Character'Val (Character'Pos ('0') + N
mod 10), Info
, Ptr
);
287 procedure Append_Info_NL
288 (Info
: in out String;
289 Ptr
: in out Natural)
292 Append_Info_Character
(ASCII
.LF
, Info
, Ptr
);
295 ------------------------
296 -- Append_Info_String --
297 ------------------------
299 procedure Append_Info_String
301 Info
: in out String;
302 Ptr
: in out Natural)
305 if Info
'Length = 0 then
309 Last
: constant Natural :=
310 Integer'Min (Ptr
+ S
'Length, Info
'Last);
312 Info
(Ptr
+ 1 .. Last
) := S
;
316 end Append_Info_String
;
318 ---------------------------------------------
319 -- Append_Info_Basic_Exception_Information --
320 ---------------------------------------------
322 -- To ease the maximum length computation, we define and pull out a couple
323 -- of string constants:
325 BEI_Name_Header
: constant String := "Exception name: ";
326 BEI_Msg_Header
: constant String := "Message: ";
327 BEI_PID_Header
: constant String := "PID: ";
329 procedure Append_Info_Basic_Exception_Information
330 (X
: Exception_Occurrence
;
331 Info
: in out String;
332 Ptr
: in out Natural)
334 Name
: String (1 .. Exception_Name_Length
(X
));
335 -- Buffer in which to fetch the exception name, in order to check
336 -- whether this is an internal _ABORT_SIGNAL or a regular occurrence.
338 Name_Ptr
: Natural := Name
'First - 1;
341 -- Output exception name and message except for _ABORT_SIGNAL, where
342 -- these two lines are omitted.
344 Append_Info_Exception_Name
(X
, Name
, Name_Ptr
);
346 if Name
(Name
'First) /= '_' then
347 Append_Info_String
(BEI_Name_Header
, Info
, Ptr
);
348 Append_Info_String
(Name
, Info
, Ptr
);
349 Append_Info_NL
(Info
, Ptr
);
351 if Exception_Message_Length
(X
) /= 0 then
352 Append_Info_String
(BEI_Msg_Header
, Info
, Ptr
);
353 Append_Info_Exception_Message
(X
, Info
, Ptr
);
354 Append_Info_NL
(Info
, Ptr
);
358 -- Output PID line if non-zero
361 Append_Info_String
(BEI_PID_Header
, Info
, Ptr
);
362 Append_Info_Nat
(X
.Pid
, Info
, Ptr
);
363 Append_Info_NL
(Info
, Ptr
);
365 end Append_Info_Basic_Exception_Information
;
367 -------------------------------------------
368 -- Basic_Exception_Information_Maxlength --
369 -------------------------------------------
371 function Basic_Exception_Info_Maxlength
372 (X
: Exception_Occurrence
) return Natural is
375 BEI_Name_Header
'Length + Exception_Name_Length
(X
) + 1
376 + BEI_Msg_Header
'Length + Exception_Message_Length
(X
) + 1
377 + BEI_PID_Header
'Length + 15;
378 end Basic_Exception_Info_Maxlength
;
380 ------------------------------------------------
381 -- Append_Info_Untailored_Exception_Traceback --
382 ------------------------------------------------
384 -- As for Basic_Exception_Information:
386 BETB_Header
: constant String := "Call stack traceback locations:";
387 LDAD_Header
: constant String := "Load address: ";
389 procedure Append_Info_Untailored_Exception_Traceback
390 (X
: Exception_Occurrence
;
391 Info
: in out String;
392 Ptr
: in out Natural)
394 Load_Address
: Address
;
397 if X
.Num_Tracebacks
= 0 then
401 -- The executable load address line
403 Load_Address
:= Get_Executable_Load_Address
;
405 if Load_Address
/= Null_Address
then
406 Append_Info_String
(LDAD_Header
, Info
, Ptr
);
407 Append_Info_Address
(Load_Address
, Info
, Ptr
);
408 Append_Info_NL
(Info
, Ptr
);
411 -- The traceback lines
412 Append_Info_String
(BETB_Header
, Info
, Ptr
);
413 Append_Info_NL
(Info
, Ptr
);
415 for J
in 1 .. X
.Num_Tracebacks
loop
416 Append_Info_Address
(TBE
.PC_For
(X
.Tracebacks
(J
)), Info
, Ptr
);
417 exit when J
= X
.Num_Tracebacks
;
418 Append_Info_Character
(' ', Info
, Ptr
);
421 Append_Info_NL
(Info
, Ptr
);
422 end Append_Info_Untailored_Exception_Traceback
;
424 ----------------------------------------------
425 -- Untailored_Exception_Traceback_Maxlength --
426 ----------------------------------------------
428 function Untailored_Exception_Traceback_Maxlength
429 (X
: Exception_Occurrence
) return Natural
431 Space_Per_Address
: constant := 2 + 16 + 1;
432 -- Space for "0x" + HHHHHHHHHHHHHHHH + " "
435 LDAD_Header
'Length + Space_Per_Address
+ BETB_Header
'Length + 1 +
436 X
.Num_Tracebacks
* Space_Per_Address
+ 1;
437 end Untailored_Exception_Traceback_Maxlength
;
439 --------------------------------------------------
440 -- Append_Info_Untailored_Exception_Information --
441 --------------------------------------------------
443 procedure Append_Info_Untailored_Exception_Information
444 (X
: Exception_Occurrence
;
445 Info
: in out String;
446 Ptr
: in out Natural)
449 Append_Info_Basic_Exception_Information
(X
, Info
, Ptr
);
450 Append_Info_Untailored_Exception_Traceback
(X
, Info
, Ptr
);
451 end Append_Info_Untailored_Exception_Information
;
453 ------------------------------
454 -- Exception_Info_Maxlength --
455 ------------------------------
457 function Exception_Info_Maxlength
458 (X
: Exception_Occurrence
) return Natural
462 Basic_Exception_Info_Maxlength
(X
)
463 + Untailored_Exception_Traceback_Maxlength
(X
);
464 end Exception_Info_Maxlength
;
466 -----------------------------------
467 -- Append_Info_Exception_Message --
468 -----------------------------------
470 procedure Append_Info_Exception_Message
471 (X
: Exception_Occurrence
;
472 Info
: in out String;
473 Ptr
: in out Natural)
476 if X
.Id
= Null_Id
then
477 raise Constraint_Error
;
481 Len
: constant Natural := Exception_Message_Length
(X
);
482 Msg
: constant String (1 .. Len
) := X
.Msg
(1 .. Len
);
484 Append_Info_String
(Msg
, Info
, Ptr
);
486 end Append_Info_Exception_Message
;
488 --------------------------------
489 -- Append_Info_Exception_Name --
490 --------------------------------
492 procedure Append_Info_Exception_Name
494 Info
: in out String;
495 Ptr
: in out Natural)
499 raise Constraint_Error
;
503 Len
: constant Natural := Exception_Name_Length
(Id
);
504 Name
: constant String (1 .. Len
) := To_Ptr
(Id
.Full_Name
) (1 .. Len
);
506 Append_Info_String
(Name
, Info
, Ptr
);
508 end Append_Info_Exception_Name
;
510 procedure Append_Info_Exception_Name
511 (X
: Exception_Occurrence
;
512 Info
: in out String;
513 Ptr
: in out Natural)
516 Append_Info_Exception_Name
(X
.Id
, Info
, Ptr
);
517 end Append_Info_Exception_Name
;
519 ---------------------------
520 -- Exception_Name_Length --
521 ---------------------------
523 function Exception_Name_Length
524 (Id
: Exception_Id
) return Natural
527 -- What is stored in the internal Name buffer includes a terminating
528 -- null character that we never care about.
530 return Id
.Name_Length
- 1;
531 end Exception_Name_Length
;
533 function Exception_Name_Length
534 (X
: Exception_Occurrence
) return Natural is
536 return Exception_Name_Length
(X
.Id
);
537 end Exception_Name_Length
;
539 ------------------------------
540 -- Exception_Message_Length --
541 ------------------------------
543 function Exception_Message_Length
544 (X
: Exception_Occurrence
) return Natural
548 end Exception_Message_Length
;
550 -------------------------------
551 -- Untailored_Exception_Traceback --
552 -------------------------------
554 function Untailored_Exception_Traceback
555 (X
: Exception_Occurrence
) return String
557 Info
: aliased String
558 (1 .. Untailored_Exception_Traceback_Maxlength
(X
));
559 Ptr
: Natural := Info
'First - 1;
561 Append_Info_Untailored_Exception_Traceback
(X
, Info
, Ptr
);
562 return Info
(Info
'First .. Ptr
);
563 end Untailored_Exception_Traceback
;
565 --------------------------------------
566 -- Untailored_Exception_Information --
567 --------------------------------------
569 function Untailored_Exception_Information
570 (X
: Exception_Occurrence
) return String
572 Info
: String (1 .. Exception_Info_Maxlength
(X
));
573 Ptr
: Natural := Info
'First - 1;
575 Append_Info_Untailored_Exception_Information
(X
, Info
, Ptr
);
576 return Info
(Info
'First .. Ptr
);
577 end Untailored_Exception_Information
;
579 -------------------------
580 -- Set_Exception_C_Msg --
581 -------------------------
583 procedure Set_Exception_C_Msg
586 Msg1
: System
.Address
;
588 Column
: Integer := 0;
589 Msg2
: System
.Address
:= System
.Null_Address
)
594 procedure Append_Number
(Number
: Integer);
595 -- Append given number to Excep.Msg
601 procedure Append_Number
(Number
: Integer) is
610 -- Compute the number of needed characters
619 -- If enough characters are available, put the line number
621 if Excep
.Msg_Length
<= Exception_Msg_Max_Length
- Size
then
622 Excep
.Msg
(Excep
.Msg_Length
+ 1) := ':';
623 Excep
.Msg_Length
:= Excep
.Msg_Length
+ Size
;
628 Remind
:= Val
rem 10;
630 Excep
.Msg
(Excep
.Msg_Length
- Size
) :=
631 Character'Val (Remind
+ Character'Pos ('0'));
637 -- Start of processing for Set_Exception_C_Msg
640 Excep
.Exception_Raised
:= False;
642 Excep
.Num_Tracebacks
:= 0;
643 Excep
.Pid
:= Local_Partition_ID
;
644 Excep
.Msg_Length
:= 0;
646 while To_Ptr
(Msg1
) (Excep
.Msg_Length
+ 1) /= ASCII
.NUL
647 and then Excep
.Msg_Length
< Exception_Msg_Max_Length
649 Excep
.Msg_Length
:= Excep
.Msg_Length
+ 1;
650 Excep
.Msg
(Excep
.Msg_Length
) := To_Ptr
(Msg1
) (Excep
.Msg_Length
);
653 Append_Number
(Line
);
654 Append_Number
(Column
);
656 -- Append second message if present
658 if Msg2
/= System
.Null_Address
659 and then Excep
.Msg_Length
+ 1 < Exception_Msg_Max_Length
661 Excep
.Msg_Length
:= Excep
.Msg_Length
+ 1;
662 Excep
.Msg
(Excep
.Msg_Length
) := ' ';
665 while To_Ptr
(Msg2
) (Ptr
) /= ASCII
.NUL
666 and then Excep
.Msg_Length
< Exception_Msg_Max_Length
668 Excep
.Msg_Length
:= Excep
.Msg_Length
+ 1;
669 Excep
.Msg
(Excep
.Msg_Length
) := To_Ptr
(Msg2
) (Ptr
);
673 end Set_Exception_C_Msg
;
675 -----------------------
676 -- Set_Exception_Msg --
677 -----------------------
679 procedure Set_Exception_Msg
684 Len
: constant Natural :=
685 Natural'Min (Message
'Length, Exception_Msg_Max_Length
);
686 First
: constant Integer := Message
'First;
688 Excep
.Exception_Raised
:= False;
689 Excep
.Msg_Length
:= Len
;
690 Excep
.Msg
(1 .. Len
) := Message
(First
.. First
+ Len
- 1);
692 Excep
.Num_Tracebacks
:= 0;
693 Excep
.Pid
:= Local_Partition_ID
;
694 end Set_Exception_Msg
;
696 ----------------------------------
697 -- Tailored_Exception_Traceback --
698 ----------------------------------
700 function Tailored_Exception_Traceback
701 (X
: Exception_Occurrence
) return String
703 -- We reference the decorator *wrapper* here and not the decorator
704 -- itself. The purpose of the local variable Wrapper is to prevent a
705 -- potential race condition in the code below. The atomicity of this
706 -- assignment is enforced by pragma Atomic in System.Soft_Links.
708 -- The potential race condition here, if no local variable was used,
709 -- relates to the test upon the wrapper's value and the call, which
710 -- are not performed atomically. With the local variable, potential
711 -- changes of the wrapper's global value between the test and the
712 -- call become inoffensive.
714 Wrapper
: constant Traceback_Decorator_Wrapper_Call
:=
715 Traceback_Decorator_Wrapper
;
718 if Wrapper
= null then
719 return Untailored_Exception_Traceback
(X
);
721 return Wrapper
.all (X
.Tracebacks
'Address, X
.Num_Tracebacks
);
723 end Tailored_Exception_Traceback
;
725 ---------------------------
726 -- Exception_Information --
727 ---------------------------
729 function Exception_Information
730 (X
: Exception_Occurrence
) return String
732 -- The tailored exception information is the basic information
733 -- associated with the tailored call chain backtrace.
735 Tback_Info
: constant String := Tailored_Exception_Traceback
(X
);
736 Tback_Len
: constant Natural := Tback_Info
'Length;
738 Info
: String (1 .. Basic_Exception_Info_Maxlength
(X
) + Tback_Len
);
739 Ptr
: Natural := Info
'First - 1;
742 Append_Info_Basic_Exception_Information
(X
, Info
, Ptr
);
743 Append_Info_String
(Tback_Info
, Info
, Ptr
);
744 return Info
(Info
'First .. Ptr
);
745 end Exception_Information
;