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_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;
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
);
287 -- Output PID line if non-zero
290 Append_Info_String
(BEI_PID_Header
, Info
, Ptr
);
291 Append_Info_Nat
(X
.Pid
, Info
, Ptr
);
292 Append_Info_NL
(Info
, Ptr
);
294 end Append_Info_Basic_Exception_Information
;
296 ---------------------------
297 -- Append_Info_Character --
298 ---------------------------
300 procedure Append_Info_Character
302 Info
: in out String;
303 Ptr
: in out Natural)
306 if Info
'Length = 0 then
308 elsif Ptr
< Info
'Last then
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)
324 if X
.Id
= Null_Id
then
325 raise Constraint_Error
;
329 Len
: constant Natural := Exception_Message_Length
(X
);
330 Msg
: constant String (1 .. Len
) := X
.Msg
(1 .. Len
);
332 Append_Info_String
(Msg
, Info
, Ptr
);
334 end Append_Info_Exception_Message
;
336 --------------------------------
337 -- Append_Info_Exception_Name --
338 --------------------------------
340 procedure Append_Info_Exception_Name
342 Info
: in out String;
343 Ptr
: in out Natural)
347 raise Constraint_Error
;
351 Len
: constant Natural := Exception_Name_Length
(Id
);
352 Name
: constant String (1 .. Len
) := To_Ptr
(Id
.Full_Name
) (1 .. Len
);
354 Append_Info_String
(Name
, Info
, Ptr
);
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)
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
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
386 Info
: in out String;
387 Ptr
: in out Natural)
391 Append_Info_Nat
(N
/ 10, Info
, Ptr
);
394 Append_Info_Character
395 (Character'Val (Character'Pos ('0') + N
mod 10), Info
, Ptr
);
402 procedure Append_Info_NL
403 (Info
: in out String;
404 Ptr
: in out Natural)
407 Append_Info_Character
(ASCII
.LF
, Info
, Ptr
);
410 ------------------------
411 -- Append_Info_String --
412 ------------------------
414 procedure Append_Info_String
416 Info
: in out String;
417 Ptr
: in out Natural)
420 if Info
'Length = 0 then
424 Last
: constant Natural :=
425 Integer'Min (Ptr
+ S
'Length, Info
'Last);
427 Info
(Ptr
+ 1 .. Last
) := S
;
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)
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
;
464 if X
.Num_Tracebacks
= 0 then
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
);
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
);
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
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;
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
535 end Exception_Message_Length
;
537 ---------------------------
538 -- Exception_Name_Length --
539 ---------------------------
541 function Exception_Name_Length
(Id
: Exception_Id
) return Natural is
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
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;
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;
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
590 Msg1
: System
.Address
;
592 Column
: Integer := 0;
593 Msg2
: System
.Address
:= System
.Null_Address
)
598 procedure Append_Number
(Number
: Integer);
599 -- Append given number to Excep.Msg
605 procedure Append_Number
(Number
: Integer) is
614 -- Compute the number of needed characters
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
;
632 Remind
:= Val
rem 10;
634 Excep
.Msg
(Excep
.Msg_Length
- Size
) :=
635 Character'Val (Remind
+ Character'Pos ('0'));
641 -- Start of processing for Set_Exception_C_Msg
644 Excep
.Exception_Raised
:= False;
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
653 Excep
.Msg_Length
:= Excep
.Msg_Length
+ 1;
654 Excep
.Msg
(Excep
.Msg_Length
) := To_Ptr
(Msg1
) (Excep
.Msg_Length
);
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
665 Excep
.Msg_Length
:= Excep
.Msg_Length
+ 1;
666 Excep
.Msg
(Excep
.Msg_Length
) := ' ';
669 while To_Ptr
(Msg2
) (Ptr
) /= ASCII
.NUL
670 and then Excep
.Msg_Length
< Exception_Msg_Max_Length
672 Excep
.Msg_Length
:= Excep
.Msg_Length
+ 1;
673 Excep
.Msg
(Excep
.Msg_Length
) := To_Ptr
(Msg2
) (Ptr
);
677 end Set_Exception_C_Msg
;
679 -----------------------
680 -- Set_Exception_Msg --
681 -----------------------
683 procedure Set_Exception_Msg
688 Len
: constant Natural :=
689 Natural'Min (Message
'Length, Exception_Msg_Max_Length
);
690 First
: constant Integer := Message
'First;
692 Excep
.Exception_Raised
:= False;
693 Excep
.Msg_Length
:= Len
;
694 Excep
.Msg
(1 .. Len
) := Message
(First
.. First
+ Len
- 1);
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
;
722 if Wrapper
= null then
723 return Untailored_Exception_Traceback
(X
);
725 return Wrapper
.all (X
.Tracebacks
'Address, X
.Num_Tracebacks
);
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 + " "
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
;