1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- ADA.EXCEPTIONS.EXCEPTION_DATA --
9 -- Copyright (C) 1992-2013, 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
41 -- There are common parts between the contents of Exception_Information
42 -- (the regular Ada interface) and Tailored_Exception_Information (what
43 -- the automatic backtracing output includes). The overall structure is
47 -- Exception_Information
51 -- Basic_Exc_Info & Basic_Exc_Tback
55 -- (B_E_I) | Exception_Name: <exception name> (as in Exception_Name)
56 -- | Message: <message> (or a null line if no message)
57 -- | PID=nnnn (if != 0)
59 -- (B_E_TB) | Call stack traceback locations:
60 -- | <0xyyyyyyyy 0xyyyyyyyy ...>
63 -- Tailored_Exception_Information
65 -- +----------+----------+
67 -- Basic_Exc_Info & Tailored_Exc_Tback
69 -- +-----------+------------+
71 -- Basic_Exc_Tback Or Tback_Decorator
72 -- if no decorator set otherwise
74 -- Functions returning String imply secondary stack use, which is a heavy
75 -- mechanism requiring run-time support. Besides, some of the routines we
76 -- provide here are to be used by the default Last_Chance_Handler, at the
77 -- critical point where the runtime is about to be finalized. Since most
78 -- of the items we have at hand are of bounded length, we also provide a
79 -- procedural interface able to incrementally append the necessary bits to
80 -- a preallocated buffer or output them straight to stderr.
82 -- The procedural interface is composed of two major sections: a neutral
83 -- section for basic types like Address, Character, Natural or String, and
84 -- an exception oriented section for the e.g. Basic_Exception_Information.
85 -- This is the Append_Info family of procedures below.
87 -- Output to stderr is commanded by passing an empty buffer to update, and
88 -- care is taken not to overflow otherwise.
90 --------------------------------------------
91 -- Procedural Interface - Neutral section --
92 --------------------------------------------
94 procedure Append_Info_Address
97 Ptr
: in out Natural);
99 procedure Append_Info_Character
101 Info
: in out String;
102 Ptr
: in out Natural);
104 procedure Append_Info_Nat
106 Info
: in out String;
107 Ptr
: in out Natural);
109 procedure Append_Info_NL
110 (Info
: in out String;
111 Ptr
: in out Natural);
112 pragma Inline
(Append_Info_NL
);
114 procedure Append_Info_String
116 Info
: in out String;
117 Ptr
: in out Natural);
119 -------------------------------------------------------
120 -- Procedural Interface - Exception oriented section --
121 -------------------------------------------------------
123 procedure Append_Info_Exception_Name
125 Info
: in out String;
126 Ptr
: in out Natural);
128 procedure Append_Info_Exception_Name
129 (X
: Exception_Occurrence
;
130 Info
: in out String;
131 Ptr
: in out Natural);
133 procedure Append_Info_Exception_Message
134 (X
: Exception_Occurrence
;
135 Info
: in out String;
136 Ptr
: in out Natural);
138 procedure Append_Info_Basic_Exception_Information
139 (X
: Exception_Occurrence
;
140 Info
: in out String;
141 Ptr
: in out Natural);
143 procedure Append_Info_Basic_Exception_Traceback
144 (X
: Exception_Occurrence
;
145 Info
: in out String;
146 Ptr
: in out Natural);
148 procedure Append_Info_Exception_Information
149 (X
: Exception_Occurrence
;
150 Info
: in out String;
151 Ptr
: in out Natural);
153 -- The "functional" interface to the exception information not involving
154 -- a traceback decorator uses preallocated intermediate buffers to avoid
155 -- the use of secondary stack. Preallocation requires preliminary length
156 -- computation, for which a series of functions are introduced:
158 ---------------------------------
159 -- Length evaluation utilities --
160 ---------------------------------
162 function Basic_Exception_Info_Maxlength
163 (X
: Exception_Occurrence
) return Natural;
165 function Basic_Exception_Tback_Maxlength
166 (X
: Exception_Occurrence
) return Natural;
168 function Exception_Info_Maxlength
169 (X
: Exception_Occurrence
) return Natural;
171 function Exception_Name_Length
172 (Id
: Exception_Id
) return Natural;
174 function Exception_Name_Length
175 (X
: Exception_Occurrence
) return Natural;
177 function Exception_Message_Length
178 (X
: Exception_Occurrence
) return Natural;
180 --------------------------
181 -- Functional Interface --
182 --------------------------
184 function Basic_Exception_Traceback
185 (X
: Exception_Occurrence
) return String;
186 -- Returns an image of the complete call chain associated with an
187 -- exception occurrence in its most basic form, that is as a raw sequence
188 -- of hexadecimal binary addresses.
190 function Tailored_Exception_Traceback
191 (X
: Exception_Occurrence
) return String;
192 -- Returns an image of the complete call chain associated with an
193 -- exception occurrence, either in its basic form if no decorator is
194 -- in place, or as formatted by the decorator otherwise.
196 -----------------------------------------------------------------------
197 -- Services for the default Last_Chance_Handler and the task wrapper --
198 -----------------------------------------------------------------------
201 (Ada
, Append_Info_Exception_Message
, "__gnat_append_info_e_msg");
204 (Ada
, Append_Info_Exception_Information
, "__gnat_append_info_e_info");
207 (Ada
, Exception_Message_Length
, "__gnat_exception_msg_len");
209 function Get_Executable_Load_Address
return System
.Address
;
210 pragma Import
(C
, Get_Executable_Load_Address
,
211 "__gnat_get_executable_load_address");
212 -- Get the load address of the executable, or Null_Address if not known
214 -------------------------
215 -- Append_Info_Address --
216 -------------------------
218 procedure Append_Info_Address
220 Info
: in out String;
221 Ptr
: in out Natural)
223 S
: String (1 .. 18);
227 H
: constant array (Integer range 0 .. 15) of Character :=
233 S
(P
) := H
(Integer (N
mod 16));
242 Append_Info_String
(S
(P
- 1 .. S
'Last), Info
, Ptr
);
243 end Append_Info_Address
;
245 ---------------------------
246 -- Append_Info_Character --
247 ---------------------------
249 procedure Append_Info_Character
251 Info
: in out String;
252 Ptr
: in out Natural)
255 if Info
'Length = 0 then
257 elsif Ptr
< Info
'Last then
261 end Append_Info_Character
;
263 ---------------------
264 -- Append_Info_Nat --
265 ---------------------
267 procedure Append_Info_Nat
269 Info
: in out String;
270 Ptr
: in out Natural)
274 Append_Info_Nat
(N
/ 10, Info
, Ptr
);
277 Append_Info_Character
278 (Character'Val (Character'Pos ('0') + N
mod 10), Info
, Ptr
);
285 procedure Append_Info_NL
286 (Info
: in out String;
287 Ptr
: in out Natural)
290 Append_Info_Character
(ASCII
.LF
, Info
, Ptr
);
293 ------------------------
294 -- Append_Info_String --
295 ------------------------
297 procedure Append_Info_String
299 Info
: in out String;
300 Ptr
: in out Natural)
303 if Info
'Length = 0 then
307 Last
: constant Natural :=
308 Integer'Min (Ptr
+ S
'Length, Info
'Last);
310 Info
(Ptr
+ 1 .. Last
) := S
;
314 end Append_Info_String
;
316 ---------------------------------------------
317 -- Append_Info_Basic_Exception_Information --
318 ---------------------------------------------
320 -- To ease the maximum length computation, we define and pull out a couple
321 -- of string constants:
323 BEI_Name_Header
: constant String := "Exception name: ";
324 BEI_Msg_Header
: constant String := "Message: ";
325 BEI_PID_Header
: constant String := "PID: ";
327 procedure Append_Info_Basic_Exception_Information
328 (X
: Exception_Occurrence
;
329 Info
: in out String;
330 Ptr
: in out Natural)
332 Name
: String (1 .. Exception_Name_Length
(X
));
333 -- Buffer in which to fetch the exception name, in order to check
334 -- whether this is an internal _ABORT_SIGNAL or a regular occurrence.
336 Name_Ptr
: Natural := Name
'First - 1;
339 -- Output exception name and message except for _ABORT_SIGNAL, where
340 -- these two lines are omitted.
342 Append_Info_Exception_Name
(X
, Name
, Name_Ptr
);
344 if Name
(Name
'First) /= '_' then
345 Append_Info_String
(BEI_Name_Header
, Info
, Ptr
);
346 Append_Info_String
(Name
, Info
, Ptr
);
347 Append_Info_NL
(Info
, Ptr
);
349 if Exception_Message_Length
(X
) /= 0 then
350 Append_Info_String
(BEI_Msg_Header
, Info
, Ptr
);
351 Append_Info_Exception_Message
(X
, Info
, Ptr
);
352 Append_Info_NL
(Info
, Ptr
);
356 -- Output PID line if non-zero
359 Append_Info_String
(BEI_PID_Header
, Info
, Ptr
);
360 Append_Info_Nat
(X
.Pid
, Info
, Ptr
);
361 Append_Info_NL
(Info
, Ptr
);
363 end Append_Info_Basic_Exception_Information
;
365 -------------------------------------------
366 -- Basic_Exception_Information_Maxlength --
367 -------------------------------------------
369 function Basic_Exception_Info_Maxlength
370 (X
: Exception_Occurrence
) return Natural is
373 BEI_Name_Header
'Length + Exception_Name_Length
(X
) + 1
374 + BEI_Msg_Header
'Length + Exception_Message_Length
(X
) + 1
375 + BEI_PID_Header
'Length + 15;
376 end Basic_Exception_Info_Maxlength
;
378 -------------------------------------------
379 -- Append_Info_Basic_Exception_Traceback --
380 -------------------------------------------
382 -- As for Basic_Exception_Information:
384 BETB_Header
: constant String := "Call stack traceback locations:";
385 LDAD_Header
: constant String := "Load address: ";
387 procedure Append_Info_Basic_Exception_Traceback
388 (X
: Exception_Occurrence
;
389 Info
: in out String;
390 Ptr
: in out Natural)
392 Load_Address
: Address
;
395 if X
.Num_Tracebacks
= 0 then
399 -- The executable load address line
401 Load_Address
:= Get_Executable_Load_Address
;
403 if Load_Address
/= Null_Address
then
404 Append_Info_String
(LDAD_Header
, Info
, Ptr
);
405 Append_Info_Address
(Load_Address
, Info
, Ptr
);
406 Append_Info_NL
(Info
, Ptr
);
409 -- The traceback lines
410 Append_Info_String
(BETB_Header
, Info
, Ptr
);
411 Append_Info_NL
(Info
, Ptr
);
413 for J
in 1 .. X
.Num_Tracebacks
loop
414 Append_Info_Address
(TBE
.PC_For
(X
.Tracebacks
(J
)), Info
, Ptr
);
415 exit when J
= X
.Num_Tracebacks
;
416 Append_Info_Character
(' ', Info
, Ptr
);
419 Append_Info_NL
(Info
, Ptr
);
420 end Append_Info_Basic_Exception_Traceback
;
422 -----------------------------------------
423 -- Basic_Exception_Traceback_Maxlength --
424 -----------------------------------------
426 function Basic_Exception_Tback_Maxlength
427 (X
: Exception_Occurrence
) return Natural
429 Space_Per_Address
: constant := 2 + 16 + 1;
430 -- Space for "0x" + HHHHHHHHHHHHHHHH + " "
433 LDAD_Header
'Length + Space_Per_Address
+ BETB_Header
'Length + 1 +
434 X
.Num_Tracebacks
* Space_Per_Address
+ 1;
435 end Basic_Exception_Tback_Maxlength
;
437 ---------------------------------------
438 -- Append_Info_Exception_Information --
439 ---------------------------------------
441 procedure Append_Info_Exception_Information
442 (X
: Exception_Occurrence
;
443 Info
: in out String;
444 Ptr
: in out Natural)
447 Append_Info_Basic_Exception_Information
(X
, Info
, Ptr
);
448 Append_Info_Basic_Exception_Traceback
(X
, Info
, Ptr
);
449 end Append_Info_Exception_Information
;
451 ------------------------------
452 -- Exception_Info_Maxlength --
453 ------------------------------
455 function Exception_Info_Maxlength
456 (X
: Exception_Occurrence
) return Natural
460 Basic_Exception_Info_Maxlength
(X
)
461 + Basic_Exception_Tback_Maxlength
(X
);
462 end Exception_Info_Maxlength
;
464 -----------------------------------
465 -- Append_Info_Exception_Message --
466 -----------------------------------
468 procedure Append_Info_Exception_Message
469 (X
: Exception_Occurrence
;
470 Info
: in out String;
471 Ptr
: in out Natural)
474 if X
.Id
= Null_Id
then
475 raise Constraint_Error
;
479 Len
: constant Natural := Exception_Message_Length
(X
);
480 Msg
: constant String (1 .. Len
) := X
.Msg
(1 .. Len
);
482 Append_Info_String
(Msg
, Info
, Ptr
);
484 end Append_Info_Exception_Message
;
486 --------------------------------
487 -- Append_Info_Exception_Name --
488 --------------------------------
490 procedure Append_Info_Exception_Name
492 Info
: in out String;
493 Ptr
: in out Natural)
497 raise Constraint_Error
;
501 Len
: constant Natural := Exception_Name_Length
(Id
);
502 Name
: constant String (1 .. Len
) := To_Ptr
(Id
.Full_Name
) (1 .. Len
);
504 Append_Info_String
(Name
, Info
, Ptr
);
506 end Append_Info_Exception_Name
;
508 procedure Append_Info_Exception_Name
509 (X
: Exception_Occurrence
;
510 Info
: in out String;
511 Ptr
: in out Natural)
514 Append_Info_Exception_Name
(X
.Id
, Info
, Ptr
);
515 end Append_Info_Exception_Name
;
517 ---------------------------
518 -- Exception_Name_Length --
519 ---------------------------
521 function Exception_Name_Length
522 (Id
: Exception_Id
) return Natural
525 -- What is stored in the internal Name buffer includes a terminating
526 -- null character that we never care about.
528 return Id
.Name_Length
- 1;
529 end Exception_Name_Length
;
531 function Exception_Name_Length
532 (X
: Exception_Occurrence
) return Natural is
534 return Exception_Name_Length
(X
.Id
);
535 end Exception_Name_Length
;
537 ------------------------------
538 -- Exception_Message_Length --
539 ------------------------------
541 function Exception_Message_Length
542 (X
: Exception_Occurrence
) return Natural
546 end Exception_Message_Length
;
548 -------------------------------
549 -- Basic_Exception_Traceback --
550 -------------------------------
552 function Basic_Exception_Traceback
553 (X
: Exception_Occurrence
) return String
555 Info
: aliased String (1 .. Basic_Exception_Tback_Maxlength
(X
));
556 Ptr
: Natural := Info
'First - 1;
558 Append_Info_Basic_Exception_Traceback
(X
, Info
, Ptr
);
559 return Info
(Info
'First .. Ptr
);
560 end Basic_Exception_Traceback
;
562 ---------------------------
563 -- Exception_Information --
564 ---------------------------
566 function Exception_Information
567 (X
: Exception_Occurrence
) return String
569 Info
: String (1 .. Exception_Info_Maxlength
(X
));
570 Ptr
: Natural := Info
'First - 1;
572 Append_Info_Exception_Information
(X
, Info
, Ptr
);
573 return Info
(Info
'First .. Ptr
);
574 end Exception_Information
;
576 -------------------------
577 -- Set_Exception_C_Msg --
578 -------------------------
580 procedure Set_Exception_C_Msg
583 Msg1
: System
.Address
;
585 Column
: Integer := 0;
586 Msg2
: System
.Address
:= System
.Null_Address
)
591 procedure Append_Number
(Number
: Integer);
592 -- Append given number to Excep.Msg
598 procedure Append_Number
(Number
: Integer) is
607 -- Compute the number of needed characters
616 -- If enough characters are available, put the line number
618 if Excep
.Msg_Length
<= Exception_Msg_Max_Length
- Size
then
619 Excep
.Msg
(Excep
.Msg_Length
+ 1) := ':';
620 Excep
.Msg_Length
:= Excep
.Msg_Length
+ Size
;
625 Remind
:= Val
rem 10;
627 Excep
.Msg
(Excep
.Msg_Length
- Size
) :=
628 Character'Val (Remind
+ Character'Pos ('0'));
634 -- Start of processing for Set_Exception_C_Msg
637 Excep
.Exception_Raised
:= False;
639 Excep
.Num_Tracebacks
:= 0;
640 Excep
.Pid
:= Local_Partition_ID
;
641 Excep
.Msg_Length
:= 0;
643 while To_Ptr
(Msg1
) (Excep
.Msg_Length
+ 1) /= ASCII
.NUL
644 and then Excep
.Msg_Length
< Exception_Msg_Max_Length
646 Excep
.Msg_Length
:= Excep
.Msg_Length
+ 1;
647 Excep
.Msg
(Excep
.Msg_Length
) := To_Ptr
(Msg1
) (Excep
.Msg_Length
);
650 Append_Number
(Line
);
651 Append_Number
(Column
);
653 -- Append second message if present
655 if Msg2
/= System
.Null_Address
656 and then Excep
.Msg_Length
+ 1 < Exception_Msg_Max_Length
658 Excep
.Msg_Length
:= Excep
.Msg_Length
+ 1;
659 Excep
.Msg
(Excep
.Msg_Length
) := ' ';
662 while To_Ptr
(Msg2
) (Ptr
) /= ASCII
.NUL
663 and then Excep
.Msg_Length
< Exception_Msg_Max_Length
665 Excep
.Msg_Length
:= Excep
.Msg_Length
+ 1;
666 Excep
.Msg
(Excep
.Msg_Length
) := To_Ptr
(Msg2
) (Ptr
);
670 end Set_Exception_C_Msg
;
672 -----------------------
673 -- Set_Exception_Msg --
674 -----------------------
676 procedure Set_Exception_Msg
681 Len
: constant Natural :=
682 Natural'Min (Message
'Length, Exception_Msg_Max_Length
);
683 First
: constant Integer := Message
'First;
685 Excep
.Exception_Raised
:= False;
686 Excep
.Msg_Length
:= Len
;
687 Excep
.Msg
(1 .. Len
) := Message
(First
.. First
+ Len
- 1);
689 Excep
.Num_Tracebacks
:= 0;
690 Excep
.Pid
:= Local_Partition_ID
;
691 end Set_Exception_Msg
;
693 ----------------------------------
694 -- Tailored_Exception_Traceback --
695 ----------------------------------
697 function Tailored_Exception_Traceback
698 (X
: Exception_Occurrence
) return String
700 -- We reference the decorator *wrapper* here and not the decorator
701 -- itself. The purpose of the local variable Wrapper is to prevent a
702 -- potential race condition in the code below. The atomicity of this
703 -- assignment is enforced by pragma Atomic in System.Soft_Links.
705 -- The potential race condition here, if no local variable was used,
706 -- relates to the test upon the wrapper's value and the call, which
707 -- are not performed atomically. With the local variable, potential
708 -- changes of the wrapper's global value between the test and the
709 -- call become inoffensive.
711 Wrapper
: constant Traceback_Decorator_Wrapper_Call
:=
712 Traceback_Decorator_Wrapper
;
715 if Wrapper
= null then
716 return Basic_Exception_Traceback
(X
);
718 return Wrapper
.all (X
.Tracebacks
'Address, X
.Num_Tracebacks
);
720 end Tailored_Exception_Traceback
;
722 ------------------------------------
723 -- Tailored_Exception_Information --
724 ------------------------------------
726 function Tailored_Exception_Information
727 (X
: Exception_Occurrence
) return String
729 -- The tailored exception information is the basic information
730 -- associated with the tailored call chain backtrace.
732 Tback_Info
: constant String := Tailored_Exception_Traceback
(X
);
733 Tback_Len
: constant Natural := Tback_Info
'Length;
735 Info
: String (1 .. Basic_Exception_Info_Maxlength
(X
) + Tback_Len
);
736 Ptr
: Natural := Info
'First - 1;
739 Append_Info_Basic_Exception_Information
(X
, Info
, Ptr
);
740 Append_Info_String
(Tback_Info
, Info
, Ptr
);
741 return Info
(Info
'First .. Ptr
);
742 end Tailored_Exception_Information
;