1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
|
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- L A S T _ C H A N C E _ H A N D L E R --
-- --
-- B o d y --
-- --
-- --
-- Copyright (C) 2008-2016, AdaCore --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- ware Foundation; either version 3, or (at your option) any later ver- --
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. --
-- --
-- --
-- --
-- --
-- --
-- You should have received a copy of the GNU General Public License and --
-- a copy of the GCC Runtime Library Exception along with this program; --
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
-- <http://www.gnu.org/licenses/>. --
-- --
-- GNAT is maintained by AdaCore (http://www.adacore.com) --
-- --
------------------------------------------------------------------------------
with System;
with System.Storage_Elements; use System.Storage_Elements;
with Interfaces.C;
with Ada.Unchecked_Conversion;
package body AUnit.Last_Chance_Handler is
Exception_Name : Message_String := null;
Exception_Message : Message_String := null;
type Jmp_Buff is array (1 .. 5) of System.Address;
type Jmp_Buff_Address is access all Jmp_Buff;
-- type expected by setjmp call
function Builtin_Setjmp (Buff : Jmp_Buff_Address) return Integer;
pragma Import (Intrinsic, Builtin_Setjmp, "__builtin_setjmp");
procedure Builtin_Longjmp (Buff : Jmp_Buff_Address; Flag : Integer);
pragma Import (Intrinsic, Builtin_Longjmp, "__builtin_longjmp");
pragma No_Return (Builtin_Longjmp);
-- handle at most 5 handlers at the same time
Jmp_Buffer : array (1 .. 5) of aliased Jmp_Buff;
Jmp_Buff_Idx : Integer := Jmp_Buffer'First;
---------------------------
-- C Strings management --
---------------------------
type chars_ptr is access all Character;
pragma No_Strict_Aliasing (chars_ptr);
function To_chars_ptr is
new Ada.Unchecked_Conversion (System.Address, chars_ptr);
function To_Address is
new Ada.Unchecked_Conversion (chars_ptr, System.Address);
function To_Ada
(Item : chars_ptr; Line : Integer := 0) return Message_String;
----------------
-- Gen_Setjmp --
----------------
function Gen_Setjmp return Integer
is
Ret : Integer;
begin
Ret := Builtin_Setjmp (Jmp_Buffer (Jmp_Buff_Idx)'Access);
if Ret = 0 then
Jmp_Buff_Idx := Jmp_Buff_Idx + 1;
Proc;
Jmp_Buff_Idx := Jmp_Buff_Idx - 1;
end if;
return Ret;
end Gen_Setjmp;
------------------------
-- Get_Exception_Name --
------------------------
function Get_Exception_Name return Message_String is
begin
if Exception_Message = null then
return AUnit.Message_Alloc (0);
else
return Exception_Name;
end if;
end Get_Exception_Name;
---------------------------
-- Get_Exception_Message --
---------------------------
function Get_Exception_Message return Message_String is
begin
if Exception_Message = null then
return AUnit.Message_Alloc (0);
else
return Exception_Message;
end if;
end Get_Exception_Message;
------------
-- To_Ada --
------------
function To_Ada
(Item : chars_ptr; Line : Integer := 0) return Message_String
is
use Interfaces.C;
Result : Message_String;
Length : size_t := 0;
Line_Img : String (1 .. Integer'Width);
First : Natural := Line_Img'Last + 1;
function "+" (Left : chars_ptr; Right : size_t) return chars_ptr;
-- Return the address Right character right of address Left.
function Peek (From : chars_ptr) return char;
-- Return the character at address From
function To_Ada (Item : char) return Character;
-- Translate char to an Ada Character
---------
-- "+" --
---------
function "+" (Left : chars_ptr; Right : size_t) return chars_ptr is
begin
return To_chars_ptr (To_Address (Left) + Storage_Offset (Right));
end "+";
----------
-- Peek --
----------
function Peek (From : chars_ptr) return char is
begin
return char (From.all);
end Peek;
------------
-- To_Ada --
------------
function To_Ada (Item : char) return Character is
begin
return Character'Val (char'Pos (Item));
end To_Ada;
begin
if Item = null then
return null;
end if;
-- Compute the Length of "Item"
loop
if Peek (Item + Length) = nul then
exit;
end if;
Length := Length + 1;
end loop;
-- Compute the image of Line
if Line /= 0 then
declare
Int : Integer;
Val : Natural;
begin
Int := Line;
loop
Val := Int mod 10;
Int := (Int - Val) / 10;
First := First - 1;
Line_Img (First) := Character'Val (Val + Character'Pos ('0'));
exit when Int = 0;
end loop;
end;
end if;
if Line /= 0 then
Result := AUnit.Message_Alloc
(Natural (Length) + Line_Img'Last - First + 2);
else
Result := AUnit.Message_Alloc (Natural (Length));
end if;
for J in 1 .. Integer (Length) loop
Result (J) := To_Ada (Peek (Item + size_t (J - 1)));
end loop;
if Line /= 0 then
Result (Integer (Length + 1)) := ':';
for J in First .. Line_Img'Last loop
Result (Integer (Length + 2) + J - First) := Line_Img (J);
end loop;
end if;
return Result;
end To_Ada;
-------------------------
-- Last_Chance_Handler --
-------------------------
procedure Last_Chance_Handler (Msg : System.Address; Line : Integer) is
procedure OS_Exit;
pragma Import (C, OS_Exit, "abort");
pragma No_Return (OS_Exit);
begin
-- Save the exception message before performing the longjmp
Exception_Name := Format ("Unexpected exception in zfp profile");
if Line = 0 then
Exception_Message := To_Ada (To_chars_ptr (Msg));
else
Exception_Message := To_Ada (To_chars_ptr (Msg), Line);
end if;
Jmp_Buff_Idx := Jmp_Buff_Idx - 1;
if Jmp_Buff_Idx >= Jmp_Buffer'First then
-- No return procedure.
Builtin_Longjmp (Jmp_Buffer (Jmp_Buff_Idx)'Access, 1);
else
OS_Exit;
end if;
end Last_Chance_Handler;
end AUnit.Last_Chance_Handler;
|