1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- A D A . E X C E P T I O N S . E X C E P T I O N _ P R O P A G A T I O N --
9 -- Copyright (C) 1992-2004 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 2, 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. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
36 with Ada.Unchecked_Conversion;
37 with Ada.Unchecked_Deallocation;
39 pragma Warnings (Off);
40 -- Since several constructs give warnings in 3.14a1, including unreferenced
41 -- variables and pragma Unreferenced itself.
43 separate (Ada.Exceptions)
44 package body Exception_Propagation is
46 ------------------------------------------------
47 -- Entities to interface with the GCC runtime --
48 ------------------------------------------------
50 -- These come from "C++ ABI for Itanium: Exception handling", which is
51 -- the reference for GCC. They are used only when we are relying on
52 -- back-end tables for exception propagation, which in turn is currenly
53 -- only the case for Zero_Cost_Exceptions in GNAT5.
55 -- Return codes from the GCC runtime functions used to propagate
58 type Unwind_Reason_Code is
60 URC_FOREIGN_EXCEPTION_CAUGHT,
70 (URC_FOREIGN_EXCEPTION_CAUGHT,
79 pragma Convention (C, Unwind_Reason_Code);
90 (UA_SEARCH_PHASE => 1,
91 UA_CLEANUP_PHASE => 2,
92 UA_HANDLER_FRAME => 4,
93 UA_FORCE_UNWIND => 8);
95 pragma Convention (C, Unwind_Action);
97 -- Mandatory common header for any exception object handled by the
98 -- GCC unwinding runtime.
100 subtype Exception_Class is Interfaces.Unsigned_64;
102 GNAT_Exception_Class : constant Exception_Class := 16#474e552d41646100#;
105 type Unwind_Word is mod 2 ** System.Word_Size;
106 for Unwind_Word'Size use System.Word_Size;
107 -- Map the corresponding C type used in Unwind_Exception below.
109 type Unwind_Exception is record
110 Class : Exception_Class := GNAT_Exception_Class;
111 Cleanup : System.Address := System.Null_Address;
112 Private1 : Unwind_Word;
113 Private2 : Unwind_Word;
115 -- Map the GCC struct used for exception handling.
117 for Unwind_Exception'Alignment use Standard'Maximum_Alignment;
118 -- The C++ ABI mandates the common exception header to be at least
119 -- doubleword aligned, and the libGCC implementation actually makes it
120 -- maximally aligned (see unwind.h). We need to match this because:
122 -- 1/ We pass pointers to such headers down to the underlying
127 -- 2/ The GNAT_GCC_Exception record below starts with this common
128 -- common header and has a C counterpart which needs to be laid
129 -- out identically in raise.c. If the alignment of the C and Ada
130 -- common headers mismatch, their size may also differ, and the
131 -- layouts may not match anymore.
133 ---------------------------------------------------------------
134 -- GNAT specific entities to deal with the GCC eh circuitry --
135 ---------------------------------------------------------------
137 -- A GNAT exception object to be dealt with by the personality routine
138 -- called by the GCC unwinding runtime. This structure shall match the
139 -- one in raise.c and is currently experimental as it might be merged
140 -- with the GNAT runtime definition some day.
142 type GNAT_GCC_Exception is record
143 Header : Unwind_Exception;
144 -- ABI Exception header first.
147 -- GNAT Exception identifier. This is used by the personality
148 -- routine to determine if the context it examines contains a
149 -- handler for the exception beeing propagated.
151 N_Cleanups_To_Trigger : Integer;
152 -- Number of cleanup only frames encountered in SEARCH phase.
153 -- This is used to control the forced unwinding triggered when
154 -- no handler has been found.
156 Next_Exception : EOA;
157 -- Used to create a linked list of exception occurrences.
160 pragma Convention (C, GNAT_GCC_Exception);
162 type GNAT_GCC_Exception_Access is access all GNAT_GCC_Exception;
164 function To_GNAT_GCC_Exception is new
165 Unchecked_Conversion (System.Address, GNAT_GCC_Exception_Access);
167 procedure Free is new Unchecked_Deallocation
168 (GNAT_GCC_Exception, GNAT_GCC_Exception_Access);
170 procedure Free is new Unchecked_Deallocation
171 (Exception_Occurrence, EOA);
175 Excep : GNAT_GCC_Exception_Access) return Boolean;
176 -- Remove Excep from the stack starting at Top.
177 -- Return True if Excep was found and removed, false otherwise.
179 -- Hooks called when entering/leaving an exception handler for a given
180 -- occurrence, aimed at handling the stack of active occurrences. The
181 -- calls are generated by gigi in tree_transform/N_Exception_Handler.
183 procedure Begin_Handler (GCC_Exception : GNAT_GCC_Exception_Access);
184 pragma Export (C, Begin_Handler, "__gnat_begin_handler");
186 procedure End_Handler (GCC_Exception : GNAT_GCC_Exception_Access);
187 pragma Export (C, End_Handler, "__gnat_end_handler");
189 function CleanupUnwind_Handler
190 (UW_Version : Integer;
191 UW_Phases : Unwind_Action;
192 UW_Eclass : Exception_Class;
193 UW_Exception : access GNAT_GCC_Exception;
194 UW_Context : System.Address;
195 UW_Argument : System.Address) return Unwind_Reason_Code;
196 -- Hook called at each step of the forced unwinding we perform to
197 -- trigger cleanups found during the propagation of an unhandled
200 -- GCC runtime functions used. These are C non-void functions, actually,
201 -- but we ignore the return values. See raise.c as to why we are using
202 -- __gnat stubs for these.
204 procedure Unwind_RaiseException
205 (UW_Exception : access GNAT_GCC_Exception);
206 pragma Import (C, Unwind_RaiseException, "__gnat_Unwind_RaiseException");
208 procedure Unwind_ForcedUnwind
209 (UW_Exception : access GNAT_GCC_Exception;
210 UW_Handler : System.Address;
211 UW_Argument : System.Address);
212 pragma Import (C, Unwind_ForcedUnwind, "__gnat_Unwind_ForcedUnwind");
214 ------------------------------------------------------------
215 -- Accessors to basic components of a GNAT exception data --
216 ------------------------------------------------------------
218 -- As of today, these are only used by the C implementation of the
219 -- propagation personality routine to avoid having to rely on a C
220 -- counterpart of the whole exception_data structure, which is both
221 -- painful and error prone. These subprograms could be moved to a
222 -- more widely visible location if need be.
224 function Is_Handled_By_Others (E : Exception_Data_Ptr) return Boolean;
225 pragma Export (C, Is_Handled_By_Others, "__gnat_is_handled_by_others");
227 function Language_For (E : Exception_Data_Ptr) return Character;
228 pragma Export (C, Language_For, "__gnat_language_for");
230 function Import_Code_For (E : Exception_Data_Ptr) return Exception_Code;
231 pragma Export (C, Import_Code_For, "__gnat_import_code_for");
239 Excep : GNAT_GCC_Exception_Access) return Boolean
241 Prev : GNAT_GCC_Exception_Access := null;
243 GCC_Exception : GNAT_GCC_Exception_Access;
249 pragma Assert (Iter.Private_Data /= System.Null_Address);
251 GCC_Exception := To_GNAT_GCC_Exception (Iter.Private_Data);
253 if GCC_Exception = Excep then
256 -- Special case for the top of the stack: shift the contents
257 -- of the next item to the top, since top is at a fixed
258 -- location and can't be changed.
260 Iter := GCC_Exception.Next_Exception;
264 -- Stack is now empty
266 Top.Private_Data := System.Null_Address;
269 Save_Occurrence_And_Private (Top.all, Iter.all);
274 Prev.Next_Exception := GCC_Exception.Next_Exception;
278 Free (GCC_Exception);
283 exit when GCC_Exception.Next_Exception = null;
285 Prev := GCC_Exception;
286 Iter := GCC_Exception.Next_Exception;
292 ---------------------------
293 -- CleanupUnwind_Handler --
294 ---------------------------
296 function CleanupUnwind_Handler
297 (UW_Version : Integer;
298 UW_Phases : Unwind_Action;
299 UW_Eclass : Exception_Class;
300 UW_Exception : access GNAT_GCC_Exception;
301 UW_Context : System.Address;
302 UW_Argument : System.Address) return Unwind_Reason_Code
305 -- Terminate as soon as we know there is nothing more to run. The
306 -- count is maintained by the personality routine.
308 if UW_Exception.N_Cleanups_To_Trigger = 0 then
309 Unhandled_Exception_Terminate;
312 -- We know there is at least one cleanup further up. Return so that it
313 -- is searched and entered, after which Unwind_Resume will be called
314 -- and this hook will gain control (with an updated count) again.
316 return URC_NO_REASON;
317 end CleanupUnwind_Handler;
319 ---------------------
320 -- Setup_Exception --
321 ---------------------
323 -- Push the current exception occurrence on the stack before overriding it.
325 procedure Setup_Exception
328 Reraised : Boolean := False)
330 Top : constant EOA := Current;
332 GCC_Exception : GNAT_GCC_Exception_Access;
334 -- Note that we make no use of the Reraised indication at this point.
336 -- The information is still passed around just in case of future needs,
337 -- since we've already switched between using/not-using it a number of
341 -- If the current exception is not live, the stack is empty and there
342 -- is nothing to do. Note that the stack always appears empty for
343 -- mechanisms that do not require one. For the mechanism we implement
344 -- in this unit, the initial Private_Data allocation for an occurrence
345 -- is issued by Propagate_Exception.
347 if Top.Private_Data = System.Null_Address then
351 -- Shift the contents of the Top of the stack in a freshly allocated
352 -- entry, which leaves the room in the fixed Top entry available for the
353 -- occurrence about to be propagated.
355 Next := new Exception_Occurrence;
356 Save_Occurrence_And_Private (Next.all, Top.all);
358 -- Allocate Private_Data for the occurrence about to be propagated
359 -- and link everything together.
361 GCC_Exception := new GNAT_GCC_Exception;
362 GCC_Exception.Next_Exception := Next;
364 Top.Private_Data := GCC_Exception.all'Address;
372 procedure Begin_Handler (GCC_Exception : GNAT_GCC_Exception_Access) is
374 -- Every necessary operation related to the occurrence stack has
375 -- already been performed by Propagate_Exception. This hook remains for
376 -- potential future necessity in optimizing the overall scheme, as well
377 -- a useful debugging tool.
385 procedure End_Handler (GCC_Exception : GNAT_GCC_Exception_Access) is
389 Removed := Remove (Get_Current_Excep.all, GCC_Exception);
390 pragma Assert (Removed);
393 -------------------------
394 -- Propagate_Exception --
395 -------------------------
397 -- Build an object suitable for the libgcc processing and call
398 -- Unwind_RaiseException to actually throw, taking care of handling
399 -- the two phase scheme it implements.
401 procedure Propagate_Exception (From_Signal_Handler : Boolean) is
402 Excep : EOA := Get_Current_Excep.all;
403 GCC_Exception : GNAT_GCC_Exception_Access;
406 if Excep.Private_Data = System.Null_Address then
407 GCC_Exception := new GNAT_GCC_Exception;
408 Excep.Private_Data := GCC_Exception.all'Address;
410 GCC_Exception := To_GNAT_GCC_Exception (Excep.Private_Data);
413 -- Fill in the useful flags for the personality routine called for each
414 -- frame via Unwind_RaiseException below.
416 GCC_Exception.Id := Excep.Id;
417 GCC_Exception.N_Cleanups_To_Trigger := 0;
419 -- Compute the backtrace for this occurrence if the corresponding
420 -- binder option has been set. Call_Chain takes care of the reraise
423 -- ??? Using Call_Chain here means we are going to walk up the stack
424 -- once only for backtracing purposes before doing it again for the
425 -- propagation per se.
427 -- The first inspection is much lighter, though, as it only requires
428 -- partial unwinding of each frame. Additionally, although we could use
429 -- the personality routine to record the addresses while propagating,
430 -- this method has two drawbacks:
432 -- 1) the trace is incomplete if the exception is handled since we
433 -- don't walk past the frame with the handler,
437 -- 2) we would miss the frames for which our personality routine is not
438 -- called, e.g. if C or C++ calls are on the way.
442 -- Perform a standard raise first. If a regular handler is found, it
443 -- will be entered after all the intermediate cleanups have run. If
444 -- there is no regular handler, control will get back to after the
445 -- call, with N_Cleanups_To_Trigger set to the number of frames with
446 -- cleanups found on the way up, and none of these already run.
448 Unwind_RaiseException (GCC_Exception);
450 -- If we get here we know the exception is not handled, as otherwise
451 -- Unwind_RaiseException arranges for the handler to be entered. Take
452 -- the necessary steps to enable the debugger to gain control while the
453 -- stack is still intact.
455 Notify_Unhandled_Exception;
457 -- Now, if cleanups have been found, run a forced unwind to trigger
458 -- them. Control should not resume there, as the unwinding hook calls
459 -- Unhandled_Exception_Terminate as soon as the last cleanup has been
462 if GCC_Exception.N_Cleanups_To_Trigger /= 0 then
463 Unwind_ForcedUnwind (GCC_Exception,
464 CleanupUnwind_Handler'Address,
465 System.Null_Address);
468 -- We get here when there is no handler or cleanup to be run at
469 -- all. The debugger has been notified before the second step above.
471 Unhandled_Exception_Terminate;
472 end Propagate_Exception;
474 ---------------------
475 -- Import_Code_For --
476 ---------------------
478 function Import_Code_For
479 (E : SSL.Exception_Data_Ptr) return Exception_Code
482 return E.all.Import_Code;
485 --------------------------
486 -- Is_Handled_By_Others --
487 --------------------------
489 function Is_Handled_By_Others
490 (E : SSL.Exception_Data_Ptr) return Boolean
493 return not E.all.Not_Handled_By_Others;
494 end Is_Handled_By_Others;
500 function Language_For
501 (E : SSL.Exception_Data_Ptr) return Character
511 -- The current model implemented for the stack of occurrences is a
512 -- simplification of previous attempts, which all prooved to be flawed or
513 -- would have needed significant additional circuitry to be made to work
516 -- We now represent every propagation by a new entry on the stack, which
517 -- means that an exception occurrence may appear more than once (e.g. when
518 -- it is reraised during the course of its own handler).
520 -- This may seem overcostly compared to the C++ model as implemented in
521 -- the g++ v3 libstd. This is actually understandable when one considers
522 -- the extra variations of possible run-time configurations induced by the
523 -- freedom offered by the Save_Occurrence/Reraise_Occurrence public
526 -- The basic point is that arranging for an occurrence to always appear at
527 -- most once on the stack requires a way to determine if a given occurence
528 -- is already there, which is not as easy as it might seem.
530 -- An attempt was made to use the Private_Data pointer for this purpose.
531 -- It did not work because:
533 -- 1/ The Private_Data has to be saved by Save_Occurrence to be usable
534 -- as a key in case of a later reraise,
536 -- 2/ There is no easy way to synchronize End_Handler for an occurrence
537 -- and the data attached to potential copies, so these copies may end
538 -- up pointing to stale data. Moreover ...
540 -- 3/ The same address may be reused for different occurrences, which
541 -- defeats the idea of using it as a key.
543 -- The example below illustrates:
545 -- Saved_CE : Exception_Occurrence;
548 -- raise Constraint_Error;
550 -- when CE: others =>
551 -- Save_Occurrence (Saved_CE, CE); <= Saved_CE.PDA = CE.PDA
554 -- <= Saved_CE.PDA is stale (!)
557 -- raise Program_Error; <= Saved_CE.PDA = PE.PDA (!!)
560 -- Reraise_Occurrence (Saved_CE);
563 -- Not releasing the Private_Data via End_Handler could be an option,
564 -- but making this to work while still avoiding memory leaks is far
567 -- The current scheme has the advantage of beeing simple, and induces
568 -- extra costs only in reraise cases which is acceptable.
570 end Exception_Propagation;