home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / adav313.zip / gnat-3_13p-os2-bin-20010916.zip / emx / gnatlib / a-except.adb < prev    next >
Text File  |  2001-07-08  |  53KB  |  1,615 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT COMPILER COMPONENTS                         --
  4. --                                                                          --
  5. --                       A D A . E X C E P T I O N S                        --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.97 $
  10. --                                                                          --
  11. --          Copyright (C) 1992-2000 Free Software Foundation, Inc.          --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  22. -- MA 02111-1307, USA.                                                      --
  23. --                                                                          --
  24. -- As a special exception,  if other files  instantiate  generics from this --
  25. -- unit, or you link  this unit with other files  to produce an executable, --
  26. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  27. -- covered  by the  GNU  General  Public  License.  This exception does not --
  28. -- however invalidate  any other reasons why  the executable file  might be --
  29. -- covered by the  GNU Public License.                                      --
  30. --                                                                          --
  31. -- GNAT was originally developed  by the GNAT team at  New York University. --
  32. -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
  33. --                                                                          --
  34. ------------------------------------------------------------------------------
  35.  
  36. pragma Polling (Off);
  37. --  We must turn polling off for this unit, because otherwise we get
  38. --  elaboration circularities with System.Exception_Tables.
  39.  
  40. with GNAT.Heap_Sort_A;        use GNAT.Heap_Sort_A;
  41.  
  42. with System;                  use System;
  43. with System.Exception_Table;  use System.Exception_Table;
  44. with System.Exceptions;       use System.Exceptions;
  45. with System.Standard_Library; use System.Standard_Library;
  46. with System.Storage_Elements; use System.Storage_Elements;
  47. with System.Soft_Links;       use System.Soft_Links;
  48. with System.Machine_State_Operations; use System.Machine_State_Operations;
  49. with System.Traceback;
  50.  
  51. with Unchecked_Conversion;
  52.  
  53. package body Ada.Exceptions is
  54.  
  55.    procedure builtin_longjmp (buffer : Address; Flag : Integer);
  56.    pragma No_Return (builtin_longjmp);
  57.    pragma Import (C, builtin_longjmp, "_gnat_builtin_longjmp");
  58.  
  59.    pragma Suppress (All_Checks);
  60.    --  We definitely do not want exceptions occurring within this unit, or
  61.    --  we are in big trouble. If an exceptional situation does occur, better
  62.    --  that it not be raised, since raising it can cause confusing chaos.
  63.  
  64.    subtype Big_Subprogram_Descriptor_List
  65.      is Subprogram_Descriptor_List (Natural);
  66.  
  67.    type Subprogram_Descriptor_List_Ptr is
  68.      access all Subprogram_Descriptor_List;
  69.  
  70.    Subprogram_Descriptors : Subprogram_Descriptor_List_Ptr;
  71.    --  This location is initialized by Register_Exceptions to point to a
  72.    --  list of pointers to procedure descriptors, sorted into ascending
  73.    --  order of PC addresses.
  74.  
  75.    Num_Subprogram_Descriptors : Natural;
  76.    --  Number of subprogram desctiptors, the useful descriptors are stored
  77.    --  in Subprogram_Descriptors (1 .. Num_Subprogram_Descriptors). There
  78.    --  can be unused entries at the end of the array due to elimination of
  79.    --  duplicated entries (which can arise from use of pragma Import).
  80.  
  81.    Exception_Tracebacks : Integer;
  82.    pragma Import (C, Exception_Tracebacks, "__gl_exception_tracebacks");
  83.    --  Boolean indicating whether tracebacks should be stored in exception
  84.    --  occurrences.
  85.  
  86.    -----------------------
  87.    -- Local Subprograms --
  88.    -----------------------
  89.  
  90.    --  Note: the exported subprograms in this package body are called directly
  91.    --  from C clients using the given external name, even though they are not
  92.    --  technically visible in the Ada sense.
  93.  
  94.    procedure AAA;
  95.    --  Mark start of procedures in this unit
  96.  
  97.    procedure ZZZ;
  98.    --  Mark end of procedures in this package
  99.  
  100.    Address_Image_Length : constant :=
  101.                             13 + 10 * Boolean'Pos (Standard'Address_Size > 32);
  102.    --  Length of string returned by Address_Image function
  103.  
  104.    function Address_Image (A : System.Address) return String;
  105.    --  Returns at string of the form 0xhhhhhhhhh for 32-bit addresses
  106.    --  or 0xhhhhhhhhhhhhhhhh for 64-bit addresses. Hex characters are
  107.    --  in lower case.
  108.  
  109.    procedure Raise_Current_Excep (E : Exception_Id);
  110.    pragma No_Return (Raise_Current_Excep);
  111.    pragma Export (C, Raise_Current_Excep, "__gnat_raise_nodefer_with_msg");
  112.    --  This is the lowest level raise routine. It raises the exception
  113.    --  referenced by Current_Excep.all in the TSD, without deferring
  114.    --  abort (the caller must ensure that abort is deferred on entry).
  115.    --  The parameter E is ignored.
  116.    --
  117.    --  This external name for Raise_Current_Excep is historical, and probably
  118.    --  should be changed but for now we keep it, because gdb knows about it.
  119.    --  The parameter is also present for historical compatibility. ???
  120.  
  121.    procedure Raise_Exception_No_Defer
  122.       (E : in Exception_Id; Message : in String := "");
  123.    pragma Export (Ada, Raise_Exception_No_Defer,
  124.      "ada__exceptions__raise_exception_no_defer");
  125.    pragma No_Return (Raise_Exception_No_Defer);
  126.    --  Similar to Raise_Exception, but with no abort deferral
  127.  
  128.    procedure Raise_With_Msg (E : Exception_Id);
  129.    pragma No_Return (Raise_With_Msg);
  130.    pragma Export (C, Raise_With_Msg, "__gnat_raise_with_msg");
  131.    --  Raises an exception with given exception id value. A message
  132.    --  is associated with the raise, and has already been stored in the
  133.    --  exception occurrence referenced by the Current_Excep in the TSD.
  134.    --  Abort is deferred before the raise call.
  135.  
  136.    procedure Reraise;
  137.    pragma No_Return (Reraise);
  138.    pragma Export (C, Reraise, "__gnat_reraise");
  139.    --  Reraises the exception referenced by the Current_Excep field of
  140.    --  the TSD (all fields of this exception occurrence are set). Abort
  141.    --  is deferred before the reraise operation.
  142.  
  143.    procedure Raise_With_Location
  144.      (E : Exception_Id;
  145.       F : SSL.Big_String_Ptr;
  146.       L : Integer);
  147.    pragma No_Return (Raise_With_Location);
  148.    --  Raise an exception with given exception id value. A filename and line
  149.    --  number is associated with the raise and is stored in the exception
  150.    --  occurrence.
  151.  
  152.    procedure Raise_Constraint_Error
  153.      (File : SSL.Big_String_Ptr; Line : Integer);
  154.    pragma No_Return (Raise_Constraint_Error);
  155.    pragma Export (C, Raise_Constraint_Error, "__gnat_raise_constraint_error");
  156.    --  Raise constraint error with file:line information
  157.  
  158.    procedure Raise_Program_Error
  159.      (File : SSL.Big_String_Ptr; Line : Integer);
  160.    pragma No_Return (Raise_Program_Error);
  161.    pragma Export (C, Raise_Program_Error, "__gnat_raise_program_error");
  162.    --  Raise program error with file:line information
  163.  
  164.    procedure Raise_Storage_Error
  165.      (File : SSL.Big_String_Ptr; Line : Integer);
  166.    pragma No_Return (Raise_Storage_Error);
  167.    pragma Export (C, Raise_Storage_Error, "__gnat_raise_storage_error");
  168.    --  Raise storage error with file:line information
  169.  
  170.    function SDP_Table_Sort_Lt (Op1, Op2 : Natural) return Boolean;
  171.    --  Used in call to sort SDP table (SDP_Table_Build), compares two elements
  172.  
  173.    procedure SDP_Table_Sort_Move (From : Natural; To : Natural);
  174.    --  Used in call to sort SDP table (SDP_Table_Build), moves one element
  175.  
  176.    procedure Set_Exception_C_Msg
  177.      (Id   : Exception_Id;
  178.       Msg  : SSL.Big_String_Ptr;
  179.       Line : Integer := 0);
  180.    --  This routine is called to setup the exception referenced by the
  181.    --  Current_Excep field in the TSD to contain the indicated Id value
  182.    --  and message. Msg is a null terminated string. when Line > 0,
  183.    --  Msg is the filename and line the line number of the exception location.
  184.  
  185.    procedure Unhandled_Exception_Terminate;
  186.    pragma No_Return (Unhandled_Exception_Terminate);
  187.    --  This procedure is called to terminate execution following an unhandled
  188.    --  exception. The exception information, including traceback if available
  189.    --  is output, and execution is then terminated. Note that at the point
  190.    --  where this routine is called, the stack has typically been destroyed
  191.  
  192.    ---------------------------------
  193.    -- Debugger Interface Routines --
  194.    ---------------------------------
  195.  
  196.    --  The routines here are null routines that normally have no effect.
  197.    --  they are provided for the debugger to place breakpoints on their
  198.    --  entry points to get control on an exception.
  199.  
  200.    procedure Notify_Exception
  201.      (Id        : Exception_Id;
  202.       Handler   : Code_Loc;
  203.       Is_Others : Boolean);
  204.    pragma Export (C, Notify_Exception, "__gnat_notify_exception");
  205.    --  This routine is called whenever an exception is signalled. The Id
  206.    --  parameter is the Exception_Id of the exception being raised. The
  207.    --  second parameter Handler is Null_Loc if the exception is unhandled,
  208.    --  and is otherwise the entry point of the handler that will handle
  209.    --  the exception. Is_Others is True if the handler is an others handler
  210.    --  and False otherwise. In the unhandled exception case, if possible
  211.    --  (and certainly if zero cost exception handling is active), the
  212.    --  stack is still intact when this procedure is called. Note that this
  213.    --  routine is entered before any finalization handlers are entered if
  214.    --  the exception is unhandled by a "real" exception handler.
  215.  
  216.    procedure Unhandled_Exception;
  217.    pragma Export (C, Unhandled_Exception, "__gnat_unhandled_exception");
  218.    --  This routine is called in addition to Notify_Exception in the
  219.    --  unhandled exception case. The fact that there are two routines
  220.    --  which are somewhat redundant is historical. Notify_Exception
  221.    --  certainly is complete enough, but GDB still uses this routine.
  222.  
  223.    --------------------------------
  224.    -- Import Run-Time C Routines --
  225.    --------------------------------
  226.  
  227.    --  The purpose of the following pragma Imports is to ensure that we
  228.    --  generate appropriate subprogram descriptors for all C routines in
  229.    --  the standard GNAT library that can raise exceptions. This ensures
  230.    --  that the exception propagation can properly find these routines
  231.  
  232.    pragma Warnings (Off);        -- so old compiler does not complain
  233.    pragma Propagate_Exceptions;
  234.  
  235.    procedure Unhandled_Terminate;
  236.    pragma Import (C, Unhandled_Terminate, "__gnat_unhandled_terminate");
  237.  
  238.    procedure GNAT_Malloc (Size : Integer_Address);
  239.    pragma Import (C, GNAT_Malloc, "__gnat_malloc");
  240.  
  241.    procedure GNAT_Realloc (Ptr : Address; Size : Integer_Address);
  242.    pragma Import (C, GNAT_Realloc, "__gnat_realloc");
  243.  
  244.    procedure Propagate_Exception (Mstate : Machine_State);
  245.    pragma No_Return (Propagate_Exception);
  246.    --  This procedure propagates the exception represented by the occurrence
  247.    --  referenced by Current_Excep in the TSD for the current task. M is
  248.    --  the initial machine state, representing the site of the exception
  249.    --  raise operation. Propagate_Exception searches the exception tables
  250.    --  for an applicable handler, calling Pop_Frame as needed. If and when
  251.    --  it locates an applicable handler Propagate_Exception makes a call
  252.    --  to Enter_Handler to actually enter the handler. If the search is
  253.    --  unable to locate an applicable handler, execution is terminated by
  254.    --  calling Unhandled_Exception_Terminate.
  255.  
  256.    procedure Call_Chain (Excep : EOA);
  257.    --  Store up to Max_Tracebacks in Excep, corresponding to the current
  258.    --  call chain.
  259.  
  260.    -----------------------
  261.    -- Polling Interface --
  262.    -----------------------
  263.  
  264.    type Unsigned is mod 2 ** 32;
  265.  
  266.    Counter : Unsigned := 0;
  267.    --  This counter is provided for convenience. It can be used in Poll to
  268.    --  perform periodic but not systematic operations.
  269.  
  270.    procedure Poll is separate;
  271.    --  The actual polling routine is separate, so that it can easily
  272.    --  be replaced with a target dependent version.
  273.  
  274.    ---------
  275.    -- AAA --
  276.    ---------
  277.  
  278.    --  This dummy procedure gives us the start of the PC range for addresses
  279.    --  within the exception unit itself. We hope that gigi/gcc keep all the
  280.    --  procedures in their original order!
  281.  
  282.    procedure AAA is
  283.    begin
  284.       null;
  285.    end AAA;
  286.  
  287.    -------------------
  288.    -- Address_Image --
  289.    -------------------
  290.  
  291.    function Address_Image (A : Address) return String is
  292.       S : String (1 .. 18);
  293.       P : Natural;
  294.       N : Integer_Address;
  295.  
  296.       H : constant array (Integer range 0 .. 15) of Character :=
  297.                                                          "0123456789abcdef";
  298.    begin
  299.       P := S'Last;
  300.       N := To_Integer (A);
  301.       while N /= 0 loop
  302.          S (P) := H (Integer (N mod 16));
  303.          P := P - 1;
  304.          N := N / 16;
  305.       end loop;
  306.  
  307.       S (P - 1) := '0';
  308.       S (P) := 'x';
  309.       return S (P - 1 .. S'Last);
  310.    end Address_Image;
  311.  
  312.    ----------------------------
  313.    -- Allocate_Machine_State --
  314.    ----------------------------
  315.  
  316.    function Allocate_Machine_State return System.Address is
  317.    begin
  318.       return System.Address
  319.         (System.Machine_State_Operations.Allocate_Machine_State);
  320.    end Allocate_Machine_State;
  321.  
  322.    -----------------
  323.    -- Break_Start --
  324.    -----------------
  325.  
  326.    procedure Break_Start is
  327.    begin
  328.       null;
  329.    end Break_Start;
  330.  
  331.    ----------------
  332.    -- Call_Chain --
  333.    ----------------
  334.  
  335.    procedure Call_Chain (Excep : EOA) is
  336.       package ST renames System.Traceback;
  337.  
  338.       M   : ST.Machine_State;
  339.       Loc : ST.Code_Loc;
  340.  
  341.    begin
  342.       if Excep.Num_Tracebacks /= 0 then
  343.          --  This is a reraise, no need to store a new (wrong) chain.
  344.          return;
  345.       end if;
  346.  
  347.       M := ST.Allocate_Machine_State;
  348.       ST.Set_Machine_State (M);
  349.       ST.Pop_Frame (M);
  350.  
  351.       loop
  352.          Loc := ST.Get_Code_Loc (M);
  353.  
  354.          exit when Loc = Null_Address
  355.            or else Excep.Num_Tracebacks = Max_Tracebacks;
  356.  
  357.          if Loc < AAA'Address or else Loc > ZZZ'Address then
  358.             Excep.Num_Tracebacks := Excep.Num_Tracebacks + 1;
  359.             Excep.Tracebacks (Excep.Num_Tracebacks) := Loc;
  360.          end if;
  361.  
  362.          ST.Pop_Frame (M);
  363.       end loop;
  364.  
  365.       ST.Free_Machine_State (M);
  366.    end Call_Chain;
  367.  
  368.    ------------------------------
  369.    -- Current_Target_Exception --
  370.    ------------------------------
  371.  
  372.    function Current_Target_Exception return Exception_Occurrence is
  373.    begin
  374.       return Null_Occurrence;
  375.    end Current_Target_Exception;
  376.  
  377.    ----------------------------
  378.    -- Deallocate_Machine_State --
  379.    ----------------------------
  380.  
  381.    procedure Deallocate_Machine_State (M : in out System.Address) is
  382.    begin
  383.       Free_Machine_State (Machine_State (M));
  384.    end Deallocate_Machine_State;
  385.  
  386.    -------------------
  387.    -- EId_To_String --
  388.    -------------------
  389.  
  390.    function EId_To_String (X : Exception_Id) return String is
  391.    begin
  392.       if X = Null_Id then
  393.          return "";
  394.       else
  395.          return Exception_Name (X);
  396.       end if;
  397.    end EId_To_String;
  398.  
  399.    ------------------
  400.    -- EO_To_String --
  401.    ------------------
  402.  
  403.    --  We use the null string to represent the null occurrence, otherwise
  404.    --  we output the Exception_Information string for the occurrence.
  405.  
  406.    function EO_To_String (X : Exception_Occurrence) return String is
  407.    begin
  408.       if X.Id = Null_Id then
  409.          return "";
  410.       else
  411.          return Exception_Information (X);
  412.       end if;
  413.    end EO_To_String;
  414.  
  415.    ------------------------
  416.    -- Exception_Identity --
  417.    ------------------------
  418.  
  419.    function Exception_Identity
  420.      (X    : Exception_Occurrence)
  421.       return Exception_Id
  422.    is
  423.    begin
  424.       if X.Id = Null_Id then
  425.          raise Constraint_Error;
  426.       else
  427.          return X.Id;
  428.       end if;
  429.    end Exception_Identity;
  430.  
  431.    ---------------------------
  432.    -- Exception_Information --
  433.    ---------------------------
  434.  
  435.    --  The format of the string is:
  436.  
  437.    --    Exception_Name: nnnnn
  438.    --    Message: mmmmm
  439.    --    PID: ppp
  440.    --    Call stack traceback locations:
  441.    --    0xhhhh 0xhhhh 0xhhhh ... 0xhhh
  442.  
  443.    --  where
  444.  
  445.    --    nnnn is the fully qualified name of the exception in all upper
  446.    --    case letters. This line is always present.
  447.  
  448.    --    mmmm is the message (this line present only if message is non-null)
  449.  
  450.    --    ppp is the Process Id value as a decimal integer (this line is
  451.    --    present only if the Process Id is non-zero). Currently we are
  452.    --    not making use of this field.
  453.  
  454.    --    The Call stack traceback locations line and the following values
  455.    --    are present only if at least one traceback location was recorded.
  456.    --    the values are given in C style format, with lower case letters
  457.    --    for a-f, and only as many digits present as are necessary.
  458.  
  459.    --  The line terminator sequence at the end of each line, including the
  460.    --  last line is a CR-LF sequence (16#0D# followed by 16#0A#).
  461.  
  462.    --  The Exception_Name and Message lines are omitted in the abort
  463.    --  signal case, since this is not really an exception, and the only
  464.    --  use of this routine is internal for printing termination output.
  465.  
  466.    --  Warning: if the format of the generated string is changed, please note
  467.    --  that an equivalent modification to the routine String_To_EO must be
  468.    --  made to preserve proper functioning of the stream attributes.
  469.  
  470.    function Exception_Information (X : Exception_Occurrence) return String is
  471.       Msg  : constant String  := Exception_Message (X);
  472.       Name : constant String  := Exception_Name (X);
  473.       Len  : constant Natural := Name'Length;
  474.       Ptr  : Natural := 0;
  475.  
  476.       --  Allocate string of more than enough length
  477.  
  478.       Info : String (1 .. Len +
  479.                           Msg'Length +
  480.                           120 +
  481.                           X.Num_Tracebacks * 18);
  482.  
  483.       procedure Add_Info_Nat (N : Natural);
  484.       --  Little internal routine to add CR.
  485.  
  486.       procedure Add_Info_NL;
  487.       --  Little internal routine to add CR/LF to information
  488.  
  489.       procedure Add_Info_String (S : String);
  490.       --  Little internal routine to add given string to information
  491.  
  492.       procedure Add_Info_Nat (N : Natural) is
  493.       begin
  494.          if N > 9 then
  495.             Add_Info_Nat (N / 10);
  496.          end if;
  497.  
  498.          Ptr := Ptr + 1;
  499.          Info (Ptr) := Character'Val (Character'Pos ('0') + N mod 10);
  500.       end Add_Info_Nat;
  501.  
  502.       procedure Add_Info_NL is
  503.       begin
  504.          Ptr := Ptr + 1;
  505.          Info (Ptr) := ASCII.CR;
  506.          Ptr := Ptr + 1;
  507.          Info (Ptr) := ASCII.LF;
  508.       end Add_Info_NL;
  509.  
  510.       procedure Add_Info_String (S : String) is
  511.       begin
  512.          Info (Ptr + 1 .. Ptr + S'Length) := S;
  513.          Ptr := Ptr + S'Length;
  514.       end Add_Info_String;
  515.  
  516.    --  Start of processing for Exception_Information
  517.  
  518.    begin
  519.       --  Output exception name and message except for _ABORT_SIGNAL, where
  520.       --  these two lines are omitted (see discussion above).
  521.  
  522.       if Name (1) /= '_' then
  523.          Add_Info_String ("Exception name: ");
  524.          Add_Info_String (Name);
  525.          Add_Info_NL;
  526.  
  527.          if Msg'Length /= 0 then
  528.             Add_Info_String ("Message: ");
  529.             Add_Info_String (Msg);
  530.             Add_Info_NL;
  531.          end if;
  532.       end if;
  533.  
  534.       --  Output PID line if non-zero
  535.  
  536.       if X.Pid /= 0 then
  537.          Add_Info_String ("PID: ");
  538.          Add_Info_Nat (X.Pid);
  539.          Add_Info_NL;
  540.       end if;
  541.  
  542.       --  Output tracebacks if present
  543.  
  544.       if X.Num_Tracebacks > 0 then
  545.          Add_Info_String ("Call stack traceback locations:");
  546.          Add_Info_NL;
  547.  
  548.          for J in 1 .. X.Num_Tracebacks loop
  549.             Add_Info_String (Address_Image (X.Tracebacks (J)));
  550.             exit when J = X.Num_Tracebacks;
  551.             Add_Info_String (" ");
  552.          end loop;
  553.  
  554.          Add_Info_NL;
  555.       end if;
  556.  
  557.       return Info (1 .. Ptr);
  558.    end Exception_Information;
  559.  
  560.    -----------------------
  561.    -- Exception_Message --
  562.    -----------------------
  563.  
  564.    function Exception_Message (X : Exception_Occurrence) return String is
  565.    begin
  566.       if X.Id = Null_Id then
  567.          raise Constraint_Error;
  568.       end if;
  569.  
  570.       return X.Msg (1 .. X.Msg_Length);
  571.    end Exception_Message;
  572.  
  573.    --------------------
  574.    -- Exception_Name --
  575.    --------------------
  576.  
  577.    function Exception_Name (X : Exception_Id) return String is
  578.    begin
  579.       if X = null then
  580.          raise Constraint_Error;
  581.       end if;
  582.  
  583.       return X.Full_Name.all (1 .. X.Name_Length - 1);
  584.    end Exception_Name;
  585.  
  586.    function Exception_Name (X : Exception_Occurrence) return String is
  587.    begin
  588.       return Exception_Name (X.Id);
  589.    end Exception_Name;
  590.  
  591.    ---------------------------
  592.    -- Exception_Name_Simple --
  593.    ---------------------------
  594.  
  595.    function Exception_Name_Simple (X : Exception_Occurrence) return String is
  596.       Name : constant String := Exception_Name (X);
  597.       P    : Natural;
  598.  
  599.    begin
  600.       P := Name'Length;
  601.       while P > 1 loop
  602.          exit when Name (P - 1) = '.';
  603.          P := P - 1;
  604.       end loop;
  605.  
  606.       return Name (P .. Name'Length);
  607.    end Exception_Name_Simple;
  608.  
  609.    -------------------------
  610.    -- Propagate_Exception --
  611.    -------------------------
  612.  
  613.    procedure Propagate_Exception (Mstate : Machine_State) is
  614.       Excep  : constant EOA := Get_Current_Excep.all;
  615.       Loc    : Code_Loc;
  616.       Lo, Hi : Natural;
  617.       Pdesc  : Natural;
  618.       Hrec   : Handler_Record_Ptr;
  619.       Info   : Subprogram_Info_Type;
  620.  
  621.       type Machine_State_Record is
  622.         new Storage_Array (1 .. Machine_State_Length);
  623.       for Machine_State_Record'Alignment use Standard'Maximum_Alignment;
  624.  
  625.       procedure Duplicate_Machine_State (Dest, Src : Machine_State);
  626.       --  Copy Src into Dest, assuming that a Machine_State is pointing to
  627.       --  an area of Machine_State_Length bytes.
  628.  
  629.       procedure Duplicate_Machine_State (Dest, Src : Machine_State) is
  630.          type Machine_State_Record_Access is access Machine_State_Record;
  631.          function To_MSR is new Unchecked_Conversion
  632.            (Machine_State, Machine_State_Record_Access);
  633.  
  634.       begin
  635.          To_MSR (Dest).all := To_MSR (Src).all;
  636.       end Duplicate_Machine_State;
  637.  
  638.       --  Data for handling the finalization handler case. A simple approach
  639.       --  in this routine would simply to unwind stack frames till we find a
  640.       --  handler and then enter it. But this is undesirable in the case where
  641.       --  we have only finalization handlers, and no "real" handler, i.e. a
  642.       --  case where we have an unhandled exception.
  643.  
  644.       --  In this case we prefer to signal unhandled exception with the stack
  645.       --  intact, and entering finalization handlers would destroy the stack
  646.       --  state. To deal with this, as we unwind the stack, we note the first
  647.       --  finalization handler, and remember it in the following variables.
  648.       --  We then continue to unwind. If and when we find a "real", i.e. non-
  649.       --  finalization handler, then we use these variables to pass control to
  650.       --  the finalization handler.
  651.  
  652.       FH_Found : Boolean := False;
  653.       --  Set when a finalization handler is found
  654.  
  655.       FH_Mstate : aliased Machine_State_Record;
  656.       --  Records the machine state for the finalization handler
  657.  
  658.       FH_Handler : Code_Loc;
  659.       --  Record handler address for finalization handler
  660.  
  661.       FH_Num_Trb : Natural;
  662.       --  Save number of tracebacks for finalization handler
  663.  
  664.    begin
  665.       --  Loop through stack frames as exception propagates
  666.  
  667.       Main_Loop : loop
  668.          <<Continue>>
  669.          Loc := Get_Code_Loc (Mstate);
  670.          exit when Loc = Null_Loc;
  671.  
  672.          --  Record location unless it is inside this unit. Note: this
  673.          --  test should really say Code_Address, but Address is the same
  674.          --  as Code_Address for unnested subprograms, and Code_Address
  675.          --  would cause a bootstrap problem
  676.  
  677.          if Loc < AAA'Address or else Loc > ZZZ'Address then
  678.  
  679.             --  Record location unless we already recorded max tracebacks
  680.  
  681.             if Excep.Num_Tracebacks /= Max_Tracebacks then
  682.  
  683.                --  Do not record location if it is the return point from
  684.                --  a reraise call from within a cleanup handler
  685.  
  686.                if not Excep.Cleanup_Flag then
  687.                   Excep.Num_Tracebacks := Excep.Num_Tracebacks + 1;
  688.                   Excep.Tracebacks (Excep.Num_Tracebacks) := Loc;
  689.  
  690.                --  For reraise call from cleanup handler, skip entry and
  691.                --  clear the flag so that we will start to record again
  692.  
  693.                else
  694.                   Excep.Cleanup_Flag := False;
  695.                end if;
  696.             end if;
  697.          end if;
  698.  
  699.          --  Do binary search on procedure table
  700.  
  701.          Lo := 1;
  702.          Hi := Num_Subprogram_Descriptors;
  703.  
  704.          --  Binary search loop
  705.  
  706.          loop
  707.             Pdesc := (Lo + Hi) / 2;
  708.  
  709.             --  Note that Loc is expected to be the procedure's call point
  710.             --  and not the return point.
  711.  
  712.             if Loc < Subprogram_Descriptors (Pdesc).Code then
  713.                Hi := Pdesc - 1;
  714.  
  715.             elsif Pdesc < Num_Subprogram_Descriptors
  716.               and then Loc > Subprogram_Descriptors (Pdesc + 1).Code
  717.             then
  718.                Lo := Pdesc + 1;
  719.  
  720.             else
  721.                exit;
  722.             end if;
  723.  
  724.             --  This happens when the current Loc is completely outside of
  725.             --  the range of the program, which usually means that we reached
  726.             --  the top level frame (e.g __start). In this case we have an
  727.             --  unhandled exception.
  728.  
  729.             exit Main_Loop when Hi < Lo;
  730.          end loop;
  731.  
  732.          --  Come here with Subprogram_Descriptors (Pdesc) referencing the
  733.          --  procedure descriptor that applies to this PC value. Now do a
  734.          --  serial search to see if any handler is applicable to this PC
  735.          --  value, and to the exception that we are propagating
  736.  
  737.          for J in 1 .. Subprogram_Descriptors (Pdesc).Num_Handlers loop
  738.             Hrec := Subprogram_Descriptors (Pdesc).Handler_Records (J);
  739.  
  740.             if Loc >= Hrec.Lo and then Loc < Hrec.Hi then
  741.  
  742.                --  PC range is applicable, see if handler is for this exception
  743.  
  744.                --  First test for case of "all others" (finalization) handler.
  745.                --  We do not enter such a handler until we are sure there is
  746.                --  a real handler further up the stack.
  747.  
  748.                if Hrec.Id = All_Others_Id then
  749.  
  750.                   --  If this is the first finalization handler, then
  751.                   --  save the machine state so we can enter it later
  752.                   --  without having to repeat the search.
  753.  
  754.                   if not FH_Found then
  755.                      FH_Found   := True;
  756.                      Duplicate_Machine_State
  757.                        (Machine_State (FH_Mstate'Address), Mstate);
  758.                      FH_Handler := Hrec.Handler;
  759.                      FH_Num_Trb := Excep.Num_Tracebacks;
  760.                   end if;
  761.  
  762.                --  Normal (non-finalization exception with matching Id)
  763.  
  764.                elsif Excep.Id = Hrec.Id
  765.                  or else (Hrec.Id = Others_Id
  766.                             and not Excep.Id.Not_Handled_By_Others)
  767.                then
  768.                   --  Notify the debugger that we have found a handler
  769.                   --  and are about to propagate an exception.
  770.  
  771.                   Notify_Exception
  772.                     (Excep.Id, Hrec.Handler, Hrec.Id = Others_Id);
  773.  
  774.                   --  If we already encountered a finalization handler, then
  775.                   --  reset the context to that handler, and enter it.
  776.  
  777.                   if FH_Found then
  778.                      Excep.Num_Tracebacks := FH_Num_Trb;
  779.                      Excep.Cleanup_Flag   := True;
  780.                      Enter_Handler
  781.                        (Machine_State (FH_Mstate'Address), FH_Handler);
  782.  
  783.                   --  If we have not encountered a finalization handler,
  784.                   --  then enter the current handler.
  785.  
  786.                   else
  787.                      Enter_Handler (Mstate, Hrec.Handler);
  788.                   end if;
  789.                end if;
  790.             end if;
  791.          end loop;
  792.  
  793.          Info := Subprogram_Descriptors (Pdesc).Subprogram_Info;
  794.          exit when Info = No_Info;
  795.          Pop_Frame (Mstate, Info);
  796.       end loop Main_Loop;
  797.  
  798.       --  Fall through if no "real" exception handler found. First thing
  799.       --  is to call the dummy Unhandled_Exception routine with the stack
  800.       --  intact, so that the debugger can get control.
  801.  
  802.       Unhandled_Exception;
  803.  
  804.       --  Also make the appropriate Notify_Exception call for the debugger.
  805.  
  806.       Notify_Exception (Excep.Id, Null_Loc, False);
  807.  
  808.       --  If there were finalization handlers, then enter the top one.
  809.       --  Just because there is no handler does not mean we don't have
  810.       --  to still execute all finalizations and cleanups before
  811.       --  terminating. Note that the process of calling cleanups
  812.       --  does not disturb the back trace stack, since he same
  813.       --  exception occurrence gets reraised, and new traceback
  814.       --  entries added as we go along.
  815.  
  816.       if FH_Found then
  817.          Excep.Num_Tracebacks := FH_Num_Trb;
  818.          Excep.Cleanup_Flag   := True;
  819.          Enter_Handler (Machine_State (FH_Mstate'Address), FH_Handler);
  820.       end if;
  821.  
  822.       --  If no cleanups, then this is the real unhandled termination
  823.  
  824.       Unhandled_Exception_Terminate;
  825.  
  826.    end Propagate_Exception;
  827.  
  828.    -------------------------
  829.    -- Raise_Current_Excep --
  830.    -------------------------
  831.  
  832.    procedure Raise_Current_Excep (E : Exception_Id) is
  833.  
  834.       pragma Inspection_Point (E);
  835.       --  This is so the debugger can reliably inspect the parameter
  836.  
  837.       Jumpbuf_Ptr : constant Address := Get_Jmpbuf_Address.all;
  838.       Mstate_Ptr  : constant Machine_State :=
  839.                       Machine_State (Get_Machine_State_Addr.all);
  840.  
  841.    begin
  842.       --  If the jump buffer pointer is non-null, it means that a jump
  843.       --  buffer was allocated (obviously that happens only in the case
  844.       --  of zero cost exceptions not implemented, or if a jump buffer
  845.       --  was manually set up by C code).
  846.  
  847.       if Jumpbuf_Ptr /= Null_Address then
  848.          if Exception_Tracebacks /= 0 then
  849.             Call_Chain (Get_Current_Excep.all);
  850.          end if;
  851.  
  852.          builtin_longjmp (Jumpbuf_Ptr, 1);
  853.  
  854.       --  If we have no jump buffer, then either zero cost exception
  855.       --  handling is in place, or we have no handlers anyway. In
  856.       --  either case we have an unhandled exception. If zero cost
  857.       --  exception handling is in place, propagate the exception
  858.  
  859.       elsif Subprogram_Descriptors /= null then
  860.          Set_Machine_State (Mstate_Ptr);
  861.          Propagate_Exception (Mstate_Ptr);
  862.  
  863.       --  Otherwise, we know the exception is unhandled by the absence
  864.       --  of an allocated jump buffer. Note that this means that we also
  865.       --  have no finalizations to do other than at the outer level.
  866.  
  867.       else
  868.          if Exception_Tracebacks /= 0 then
  869.             Call_Chain (Get_Current_Excep.all);
  870.          end if;
  871.  
  872.          Unhandled_Exception;
  873.          Notify_Exception (E, Null_Loc, False);
  874.          Unhandled_Exception_Terminate;
  875.       end if;
  876.    end Raise_Current_Excep;
  877.  
  878.    --------------------
  879.    -- Raise_Exception --
  880.    ---------------------
  881.  
  882.    procedure Raise_Exception
  883.      (E       : in Exception_Id;
  884.       Message : in String := "")
  885.    is
  886.       Len : constant Natural :=
  887.               Natural'Min (Message'Length, Exception_Msg_Max_Length);
  888.  
  889.       Excep : constant EOA := Get_Current_Excep.all;
  890.  
  891.    begin
  892.       if E /= null then
  893.          Excep.Msg_Length := Len;
  894.          Excep.Msg (1 .. Len) := Message (1 .. Len);
  895.          Raise_With_Msg (E);
  896.       end if;
  897.    end Raise_Exception;
  898.  
  899.    -------------------------------
  900.    -- Raise_From_Signal_Handler --
  901.    -------------------------------
  902.  
  903.    procedure Raise_From_Signal_Handler
  904.      (E : Exception_Id;
  905.       M : SSL.Big_String_Ptr)
  906.    is
  907.       Jumpbuf_Ptr : constant Address := Get_Jmpbuf_Address.all;
  908.       Mstate_Ptr  : constant Machine_State :=
  909.                       Machine_State (Get_Machine_State_Addr.all);
  910.  
  911.    begin
  912.       Set_Exception_C_Msg (E, M);
  913.       Abort_Defer.all;
  914.  
  915.       --  Now we raise the exception. The following code is essentially
  916.       --  identical to the Raise_Current_Excep routine, except that in the
  917.       --  zero cost exception case, we do not call Set_Machine_State, since
  918.       --  the signal handler that passed control here has already set the
  919.       --  machine state directly.
  920.  
  921.       --  If the jump buffer pointer is non-null, it means that a jump
  922.       --  buffer was allocated (obviously that happens only in the case
  923.       --  of zero cost exceptions not implemented, or if a jump buffer
  924.       --  was manually set up by C code).
  925.  
  926.       if Jumpbuf_Ptr /= Null_Address then
  927.          builtin_longjmp (Jumpbuf_Ptr, 1);
  928.  
  929.       --  If we have no jump buffer, then either zero cost exception
  930.       --  handling is in place, or we have no handlers anyway. In
  931.       --  either case we have an unhandled exception. If zero cost
  932.       --  exception handling is in place, propagate the exception
  933.  
  934.       elsif Subprogram_Descriptors /= null then
  935.          Propagate_Exception (Mstate_Ptr);
  936.  
  937.       --  Otherwise, we know the exception is unhandled by the absence
  938.       --  of an allocated jump buffer. Note that this means that we also
  939.       --  have no finalizations to do other than at the outer level.
  940.  
  941.       else
  942.          Unhandled_Exception;
  943.          Unhandled_Exception_Terminate;
  944.       end if;
  945.    end Raise_From_Signal_Handler;
  946.  
  947.    ------------------
  948.    -- Raise_No_Msg --
  949.    ------------------
  950.  
  951.    procedure Raise_No_Msg (E : Exception_Id) is
  952.       Excep : constant EOA := Get_Current_Excep.all;
  953.  
  954.    begin
  955.       Excep.Msg_Length := 0;
  956.       Raise_With_Msg (E);
  957.    end Raise_No_Msg;
  958.  
  959.    -------------------------
  960.    -- Raise_With_Location --
  961.    -------------------------
  962.  
  963.    procedure Raise_With_Location
  964.      (E : Exception_Id;
  965.       F : SSL.Big_String_Ptr;
  966.       L : Integer) is
  967.    begin
  968.       Set_Exception_C_Msg (E, F, L);
  969.       Abort_Defer.all;
  970.       Raise_Current_Excep (E);
  971.    end Raise_With_Location;
  972.  
  973.    ----------------------------
  974.    -- Raise_Constraint_Error --
  975.    ----------------------------
  976.  
  977.    procedure Raise_Constraint_Error
  978.      (File : SSL.Big_String_Ptr; Line : Integer) is
  979.    begin
  980.       Raise_With_Location (Constraint_Error_Def'Access, File, Line);
  981.    end Raise_Constraint_Error;
  982.  
  983.    -------------------------
  984.    -- Raise_Program_Error --
  985.    -------------------------
  986.  
  987.    procedure Raise_Program_Error
  988.      (File : SSL.Big_String_Ptr; Line : Integer) is
  989.    begin
  990.       Raise_With_Location (Program_Error_Def'Access, File, Line);
  991.    end Raise_Program_Error;
  992.  
  993.    -------------------------
  994.    -- Raise_Storage_Error --
  995.    -------------------------
  996.  
  997.    procedure Raise_Storage_Error
  998.      (File : SSL.Big_String_Ptr; Line : Integer) is
  999.    begin
  1000.       Raise_With_Location (Storage_Error_Def'Access, File, Line);
  1001.    end Raise_Storage_Error;
  1002.  
  1003.    ----------------------
  1004.    -- Raise_With_C_Msg --
  1005.    ----------------------
  1006.  
  1007.    procedure Raise_With_C_Msg
  1008.      (E    : Exception_Id;
  1009.       M    : SSL.Big_String_Ptr) is
  1010.    begin
  1011.       Set_Exception_C_Msg (E, M);
  1012.       Abort_Defer.all;
  1013.       Raise_Current_Excep (E);
  1014.    end Raise_With_C_Msg;
  1015.  
  1016.    --------------------
  1017.    -- Raise_With_Msg --
  1018.    --------------------
  1019.  
  1020.    procedure Raise_With_Msg (E : Exception_Id) is
  1021.       Excep : constant EOA := Get_Current_Excep.all;
  1022.  
  1023.    begin
  1024.       Excep.Id             := E;
  1025.       Excep.Num_Tracebacks := 0;
  1026.       Excep.Cleanup_Flag   := False;
  1027.       Excep.Pid            := Local_Partition_ID;
  1028.       Abort_Defer.all;
  1029.       Raise_Current_Excep (E);
  1030.    end Raise_With_Msg;
  1031.  
  1032.    -------------
  1033.    -- Reraise --
  1034.    -------------
  1035.  
  1036.    procedure Reraise is
  1037.       Excep : constant EOA := Get_Current_Excep.all;
  1038.  
  1039.    begin
  1040.       Abort_Defer.all;
  1041.       Raise_Current_Excep (Excep.Id);
  1042.    end Reraise;
  1043.  
  1044.    ------------------------
  1045.    -- Reraise_Occurrence --
  1046.    ------------------------
  1047.  
  1048.    procedure Reraise_Occurrence (X : Exception_Occurrence) is
  1049.    begin
  1050.       if X.Id /= null then
  1051.          Abort_Defer.all;
  1052.          Save_Occurrence (Get_Current_Excep.all.all, X);
  1053.          Raise_Current_Excep (X.Id);
  1054.       end if;
  1055.    end Reraise_Occurrence;
  1056.  
  1057.    ---------------------------------
  1058.    -- Reraise_Occurrence_No_Defer --
  1059.    ---------------------------------
  1060.  
  1061.    procedure Reraise_Occurrence_No_Defer (X : Exception_Occurrence) is
  1062.    begin
  1063.       Save_Occurrence (Get_Current_Excep.all.all, X);
  1064.       Raise_Current_Excep (X.Id);
  1065.    end Reraise_Occurrence_No_Defer;
  1066.  
  1067.    ---------------------
  1068.    -- Save_Occurrence --
  1069.    ---------------------
  1070.  
  1071.    procedure Save_Occurrence
  1072.      (Target : out Exception_Occurrence;
  1073.       Source : in  Exception_Occurrence)
  1074.    is
  1075.    begin
  1076.       Target.Id             := Source.Id;
  1077.       Target.Msg_Length     := Source.Msg_Length;
  1078.       Target.Num_Tracebacks := Source.Num_Tracebacks;
  1079.       Target.Pid            := Source.Pid;
  1080.       Target.Cleanup_Flag   := Source.Cleanup_Flag;
  1081.  
  1082.       Target.Msg (1 .. Target.Msg_Length) :=
  1083.         Source.Msg (1 .. Target.Msg_Length);
  1084.  
  1085.       Target.Tracebacks (1 .. Target.Num_Tracebacks) :=
  1086.         Source.Tracebacks (1 .. Target.Num_Tracebacks);
  1087.    end Save_Occurrence;
  1088.  
  1089.    function Save_Occurrence
  1090.      (Source : in Exception_Occurrence)
  1091.       return   EOA
  1092.    is
  1093.       Target : EOA := new Exception_Occurrence;
  1094.  
  1095.    begin
  1096.       Save_Occurrence (Target.all, Source);
  1097.       return Target;
  1098.    end Save_Occurrence;
  1099.  
  1100.    ---------------------
  1101.    -- SDP_Table_Build --
  1102.    ---------------------
  1103.  
  1104.    procedure SDP_Table_Build
  1105.      (SDP_Addresses   : System.Address;
  1106.       SDP_Count       : Natural;
  1107.       Elab_Addresses  : System.Address;
  1108.       Elab_Addr_Count : Natural)
  1109.    is
  1110.       type SDLP_Array is array (1 .. SDP_Count) of Subprogram_Descriptors_Ptr;
  1111.       type SDLP_Array_Ptr is access all SDLP_Array;
  1112.  
  1113.       function To_SDLP_Array_Ptr is new Unchecked_Conversion
  1114.         (System.Address, SDLP_Array_Ptr);
  1115.  
  1116.       T : constant SDLP_Array_Ptr := To_SDLP_Array_Ptr (SDP_Addresses);
  1117.  
  1118.       type Elab_Array is array (1 .. Elab_Addr_Count) of Code_Loc;
  1119.       type Elab_Array_Ptr is access all Elab_Array;
  1120.  
  1121.       function To_Elab_Array_Ptr is new Unchecked_Conversion
  1122.         (System.Address, Elab_Array_Ptr);
  1123.  
  1124.       EA : constant Elab_Array_Ptr := To_Elab_Array_Ptr (Elab_Addresses);
  1125.  
  1126.       Ndes : Natural;
  1127.  
  1128.    begin
  1129.       --  First count number of subprogram descriptors. This count includes
  1130.       --  entries with duplicated code addresses (resulting from Import).
  1131.  
  1132.       Ndes := Elab_Addr_Count;
  1133.       for J in T'Range loop
  1134.          Ndes := Ndes + T (J).Count;
  1135.       end loop;
  1136.  
  1137.       --  Now allocate the table (extra zero'th element is for sort call)
  1138.  
  1139.       Subprogram_Descriptors := new Subprogram_Descriptor_List (0 .. Ndes);
  1140.  
  1141.       --  First copy in the elaboration routine addresses, building dummy
  1142.       --  SDP's for them as we go through the list.
  1143.  
  1144.       Ndes := 0;
  1145.       for J in EA'Range loop
  1146.          Ndes := Ndes + 1;
  1147.          Subprogram_Descriptors (Ndes) := new Subprogram_Descriptor_0;
  1148.  
  1149.          Subprogram_Descriptors (Ndes).all :=
  1150.            Subprogram_Descriptor'
  1151.              (Num_Handlers    => 0,
  1152.               Code            => EA (J),
  1153.               Subprogram_Info => EA (J),
  1154.               Handler_Records => (1 .. 0 => null));
  1155.       end loop;
  1156.  
  1157.       --  Now copy in pointers to SDP addresses of application subprograms
  1158.  
  1159.       for J in T'Range loop
  1160.          for K in 1 .. T (J).Count loop
  1161.             Ndes := Ndes + 1;
  1162.             Subprogram_Descriptors (Ndes) := T (J).SDesc (K);
  1163.          end loop;
  1164.       end loop;
  1165.  
  1166.       --  Now we need to sort the table into ascending PC order
  1167.  
  1168.       Sort (Ndes, SDP_Table_Sort_Move'Access, SDP_Table_Sort_Lt'Access);
  1169.  
  1170.       --  Now eliminate duplicate entries. Note that in the case where
  1171.       --  entries have duplicate code addresses, the code for the Lt
  1172.       --  routine ensures that the interesting one (i.e. the one with
  1173.       --  handler entries if there are any) comes first.
  1174.  
  1175.       Num_Subprogram_Descriptors := 1;
  1176.  
  1177.       for J in 2 .. Ndes loop
  1178.          if Subprogram_Descriptors (J).Code /=
  1179.             Subprogram_Descriptors (Num_Subprogram_Descriptors).Code
  1180.          then
  1181.             Num_Subprogram_Descriptors := Num_Subprogram_Descriptors + 1;
  1182.             Subprogram_Descriptors (Num_Subprogram_Descriptors) :=
  1183.               Subprogram_Descriptors (J);
  1184.          end if;
  1185.       end loop;
  1186.  
  1187.    end SDP_Table_Build;
  1188.  
  1189.    -----------------------
  1190.    -- SDP_Table_Sort_Lt --
  1191.    -----------------------
  1192.  
  1193.    function SDP_Table_Sort_Lt (Op1, Op2 : Natural) return Boolean is
  1194.       SDC1 : constant Code_Loc := Subprogram_Descriptors (Op1).Code;
  1195.       SDC2 : constant Code_Loc := Subprogram_Descriptors (Op2).Code;
  1196.  
  1197.    begin
  1198.       if SDC1 < SDC2 then
  1199.          return True;
  1200.  
  1201.       elsif SDC1 > SDC2 then
  1202.          return False;
  1203.  
  1204.       --  For two descriptors for the same procedure, we want the more
  1205.       --  interesting one first. A descriptor with an exception handler
  1206.       --  is more interesting than one without. This happens if the less
  1207.       --  interesting one came from a pragma Import.
  1208.  
  1209.       else
  1210.          return Subprogram_Descriptors (Op1).Num_Handlers /= 0
  1211.            and then Subprogram_Descriptors (Op2).Num_Handlers = 0;
  1212.       end if;
  1213.    end SDP_Table_Sort_Lt;
  1214.  
  1215.    --------------------------
  1216.    -- SDP_Table_Sort_Move --
  1217.    --------------------------
  1218.  
  1219.    procedure SDP_Table_Sort_Move (From : Natural; To : Natural) is
  1220.    begin
  1221.       Subprogram_Descriptors (To) := Subprogram_Descriptors (From);
  1222.    end SDP_Table_Sort_Move;
  1223.  
  1224.    -------------------------
  1225.    -- Set_Exception_C_Msg --
  1226.    -------------------------
  1227.  
  1228.    procedure Set_Exception_C_Msg
  1229.      (Id   : Exception_Id;
  1230.       Msg  : Big_String_Ptr;
  1231.       Line : Integer := 0)
  1232.    is
  1233.       Excep  : constant EOA := Get_Current_Excep.all;
  1234.       Val    : Integer := Line;
  1235.       Remind : Integer;
  1236.       Size   : Integer := 1;
  1237.  
  1238.    begin
  1239.       Excep.Id             := Id;
  1240.       Excep.Num_Tracebacks := 0;
  1241.       Excep.Pid            := Local_Partition_ID;
  1242.       Excep.Msg_Length     := 0;
  1243.       Excep.Cleanup_Flag   := False;
  1244.  
  1245.       while Msg (Excep.Msg_Length + 1) /= ASCII.NUL
  1246.         and then Excep.Msg_Length < Exception_Msg_Max_Length
  1247.       loop
  1248.          Excep.Msg_Length := Excep.Msg_Length + 1;
  1249.          Excep.Msg (Excep.Msg_Length) := Msg (Excep.Msg_Length);
  1250.       end loop;
  1251.  
  1252.       if Line > 0 then
  1253.          --  Compute the number of needed characters
  1254.  
  1255.          while Val > 0 loop
  1256.             Val := Val / 10;
  1257.             Size := Size + 1;
  1258.          end loop;
  1259.  
  1260.          --  If enough characters are available, put the line number
  1261.  
  1262.          if Excep.Msg_Length <= Exception_Msg_Max_Length - Size then
  1263.             Excep.Msg (Excep.Msg_Length + 1) := ':';
  1264.             Excep.Msg_Length := Excep.Msg_Length + Size;
  1265.             Val := Line;
  1266.             Size := 0;
  1267.  
  1268.             while Val > 0 loop
  1269.                Remind := Val rem 10;
  1270.                Val := Val / 10;
  1271.                Excep.Msg (Excep.Msg_Length - Size) :=
  1272.                  Character'Val (Remind + Character'Pos ('0'));
  1273.                Size := Size + 1;
  1274.             end loop;
  1275.          end if;
  1276.       end if;
  1277.    end Set_Exception_C_Msg;
  1278.  
  1279.    -------------------
  1280.    -- String_To_EId --
  1281.    -------------------
  1282.  
  1283.    function String_To_EId (S : String) return Exception_Id is
  1284.    begin
  1285.       if S = "" then
  1286.          return Null_Id;
  1287.       else
  1288.          return Exception_Id (Internal_Exception (S));
  1289.       end if;
  1290.    end String_To_EId;
  1291.  
  1292.    X : Exception_Occurrence;
  1293.    --  This should be inside String_To_EO, it is outside to temporarily
  1294.    --  get around a bootstrap problem.
  1295.  
  1296.    ------------------
  1297.    -- String_To_EO --
  1298.    ------------------
  1299.  
  1300.    function String_To_EO (S : String) return Exception_Occurrence is
  1301.       From : Natural;
  1302.       To   : Integer;
  1303.  
  1304.       procedure Bad_EO;
  1305.       --  Signal bad exception occurrence string
  1306.  
  1307.       procedure Next_String;
  1308.       --  On entry, To points to last character of previous line of the
  1309.       --  message, terminated by CR/LF. On return, From .. To are set to
  1310.       --  specify the next string, or From > To if there are no more lines.
  1311.  
  1312.       procedure Bad_EO is
  1313.       begin
  1314.          Raise_Exception
  1315.            (Program_Error'Identity,
  1316.             "bad exception occurrence in stream input");
  1317.       end Bad_EO;
  1318.  
  1319.       procedure Next_String is
  1320.       begin
  1321.          From := To + 3;
  1322.  
  1323.          if From < S'Last then
  1324.             To := From + 1;
  1325.  
  1326.             while To < S'Last - 2 loop
  1327.                if To >= S'Last then
  1328.                   Bad_EO;
  1329.                elsif S (To + 1) = ASCII.CR then
  1330.                   exit;
  1331.                else
  1332.                   To := To + 1;
  1333.                end if;
  1334.             end loop;
  1335.          end if;
  1336.       end Next_String;
  1337.  
  1338.    --  Start of processing for String_To_EO
  1339.  
  1340.    begin
  1341.       if S = "" then
  1342.          return Null_Occurrence;
  1343.  
  1344.       else
  1345.          X.Cleanup_Flag := False;
  1346.  
  1347.          To := S'First - 3;
  1348.          Next_String;
  1349.  
  1350.          if S (From .. From + 15) /= "Exception name: " then
  1351.             Bad_EO;
  1352.          end if;
  1353.  
  1354.          X.Id := Exception_Id (Internal_Exception (S (From + 16 .. To)));
  1355.  
  1356.          Next_String;
  1357.  
  1358.          if From <= To and then S (From) = 'M' then
  1359.             if S (From .. From + 8) /= "Message: " then
  1360.                Bad_EO;
  1361.             end if;
  1362.  
  1363.             X.Msg_Length := To - From - 8;
  1364.             X.Msg (1 .. X.Msg_Length) := S (From + 9 .. To);
  1365.             Next_String;
  1366.  
  1367.          else
  1368.             X.Msg_Length := 0;
  1369.          end if;
  1370.  
  1371.          X.Pid := 0;
  1372.  
  1373.          if From <= To and then S (From) = 'P' then
  1374.             if S (From .. From + 3) /= "PID:" then
  1375.                Bad_EO;
  1376.             end if;
  1377.  
  1378.             From := From + 5; -- skip past PID: space
  1379.  
  1380.             while From <= To loop
  1381.                X.Pid := X.Pid * 10 +
  1382.                           (Character'Pos (S (From)) - Character'Pos ('0'));
  1383.                From := From + 1;
  1384.             end loop;
  1385.  
  1386.             Next_String;
  1387.          end if;
  1388.  
  1389.          X.Num_Tracebacks := 0;
  1390.  
  1391.          if From <= To then
  1392.             if S (From .. To) /= "Call stack traceback locations:" then
  1393.                Bad_EO;
  1394.             end if;
  1395.  
  1396.             Next_String;
  1397.             loop
  1398.                exit when From > To;
  1399.  
  1400.                declare
  1401.                   Ch : Character;
  1402.                   C  : Integer_Address;
  1403.                   N  : Integer_Address;
  1404.  
  1405.                begin
  1406.  
  1407.                   if S (From) /= '0'
  1408.                     or else S (From + 1) /= 'x'
  1409.                   then
  1410.                      Bad_EO;
  1411.                   else
  1412.                      From := From + 2;
  1413.                   end if;
  1414.  
  1415.                   C := 0;
  1416.                   while From <= To loop
  1417.                      Ch := S (From);
  1418.  
  1419.                      if Ch in '0' .. '9' then
  1420.                         N :=
  1421.                           Character'Pos (S (From)) - Character'Pos ('0');
  1422.  
  1423.                      elsif Ch in 'a' .. 'f' then
  1424.                         N :=
  1425.                           Character'Pos (S (From)) - Character'Pos ('a') + 10;
  1426.  
  1427.                      elsif Ch = ' ' then
  1428.                         From := From + 1;
  1429.                         exit;
  1430.  
  1431.                      else
  1432.                         Bad_EO;
  1433.                      end if;
  1434.  
  1435.                      C := C * 16 + N;
  1436.  
  1437.                      From := From + 1;
  1438.                   end loop;
  1439.  
  1440.                   if X.Num_Tracebacks = Max_Tracebacks then
  1441.                      Bad_EO;
  1442.                   end if;
  1443.  
  1444.                   X.Num_Tracebacks := X.Num_Tracebacks + 1;
  1445.                   X.Tracebacks (X.Num_Tracebacks) := To_Address (C);
  1446.                end;
  1447.             end loop;
  1448.          end if;
  1449.  
  1450.          return X;
  1451.       end if;
  1452.    end String_To_EO;
  1453.  
  1454.    -------------------------
  1455.    -- Unhandled_Exception --
  1456.    -------------------------
  1457.  
  1458.    procedure Unhandled_Exception is
  1459.    begin
  1460.       null;
  1461.    end Unhandled_Exception;
  1462.  
  1463.    ----------------------
  1464.    -- Notify_Exception --
  1465.    ----------------------
  1466.  
  1467.    procedure Notify_Exception
  1468.      (Id        : Exception_Id;
  1469.       Handler   : Code_Loc;
  1470.       Is_Others : Boolean)
  1471.    is
  1472.    begin
  1473.       null;
  1474.    end Notify_Exception;
  1475.  
  1476.    -----------------------------------
  1477.    -- Unhandled_Exception_Terminate --
  1478.    -----------------------------------
  1479.  
  1480.    adafinal_Called : Boolean := False;
  1481.    --  Used to prevent recursive call to adafinal in the event that
  1482.    --  adafinal processing itself raises an unhandled exception.
  1483.  
  1484.    type Subprogram_Ptr is access procedure;
  1485.    adafinal_Ptr : Subprogram_Ptr;
  1486.    pragma Import (C, adafinal_Ptr, "__gl_adafinal_ptr");
  1487.    --  Used to get hold of adafinal address in generated binder program
  1488.  
  1489.    type FILEs is new System.Address;
  1490.    type int is new Integer;
  1491.  
  1492.    procedure Unhandled_Exception_Terminate is
  1493.       Excep : constant EOA    := Get_Current_Excep.all;
  1494.       Msg   : constant String := Exception_Message (Excep.all);
  1495.       Nline : constant String := String'(1 => ASCII.LF);
  1496.  
  1497.       procedure To_Stderr (S : String);
  1498.       --  Little routine to output string to stderr
  1499.  
  1500.       procedure To_Stderr (S : String) is
  1501.          procedure put_char_stderr (C : int);
  1502.          pragma Import (C, put_char_stderr, "put_char_stderr");
  1503.  
  1504.       begin
  1505.          for J in 1 .. S'Length loop
  1506.             if S (J) /= ASCII.CR then
  1507.                put_char_stderr (Character'Pos (S (J)));
  1508.             end if;
  1509.          end loop;
  1510.       end To_Stderr;
  1511.  
  1512.    --  Start of processing for Unhandled_Exception_Terminate
  1513.  
  1514.    begin
  1515.       --  First call adafinal
  1516.  
  1517.       if not adafinal_Called then
  1518.          adafinal_Called := True;
  1519.          adafinal_Ptr.all;
  1520.       end if;
  1521.  
  1522.       --  Check for special case of raising _ABORT_SIGNAL, which is not
  1523.       --  really an exception at all. We recognize this by the fact that
  1524.       --  it is the only exception whose name starts with underscore.
  1525.  
  1526.       if Exception_Name (Excep.all) (1) = '_' then
  1527.          To_Stderr (Nline);
  1528.          To_Stderr ("Execution terminated by abort of environment task");
  1529.          To_Stderr (Nline);
  1530.  
  1531.       --  If no tracebacks, we print the unhandled exception in the old style
  1532.       --  (i.e. the style used before ZCX was implemented). We do this to
  1533.       --  retain compatibility, especially with the nightly scripts, but
  1534.       --  this can be removed at some point ???
  1535.  
  1536.       elsif Excep.Num_Tracebacks = 0 then
  1537.          To_Stderr (Nline);
  1538.          To_Stderr ("raised ");
  1539.          To_Stderr (Exception_Name (Excep.all));
  1540.  
  1541.          if Msg'Length /= 0 then
  1542.             To_Stderr (" : ");
  1543.             To_Stderr (Msg);
  1544.          end if;
  1545.  
  1546.          To_Stderr (Nline);
  1547.  
  1548.       --  New style, zero cost exception case
  1549.  
  1550.       else
  1551.          To_Stderr (Nline);
  1552.          To_Stderr ("Execution terminated by unhandled exception");
  1553.          To_Stderr (Nline);
  1554.          To_Stderr (Exception_Information (Excep.all));
  1555.       end if;
  1556.  
  1557.       --  Perform system dependent shutdown code
  1558.  
  1559.       declare
  1560.          procedure Unhandled_Terminate;
  1561.          pragma No_Return (Unhandled_Terminate);
  1562.          pragma Import
  1563.            (C, Unhandled_Terminate, "__gnat_unhandled_terminate");
  1564.  
  1565.       begin
  1566.          Unhandled_Terminate;
  1567.       end;
  1568.  
  1569.    end Unhandled_Exception_Terminate;
  1570.  
  1571.    ------------------------------
  1572.    -- Raise_Exception_No_Defer --
  1573.    ------------------------------
  1574.  
  1575.    procedure Raise_Exception_No_Defer
  1576.      (E       : in Exception_Id;
  1577.       Message : in String := "")
  1578.    is
  1579.       Len : constant Natural :=
  1580.               Natural'Min (Message'Length, Exception_Msg_Max_Length);
  1581.  
  1582.       Excep : constant EOA := Get_Current_Excep.all;
  1583.  
  1584.    begin
  1585.       Excep.Msg_Length := Len;
  1586.       Excep.Msg (1 .. Len) := Message (1 .. Len);
  1587.       Excep.Id             := E;
  1588.       Excep.Num_Tracebacks := 0;
  1589.       Excep.Cleanup_Flag   := False;
  1590.       Excep.Pid            := Local_Partition_ID;
  1591.  
  1592.       --  DO NOT CALL Abort_Defer.all; !!!!
  1593.  
  1594.       Raise_Current_Excep (E);
  1595.    end Raise_Exception_No_Defer;
  1596.  
  1597.    ---------
  1598.    -- ZZZ --
  1599.    ---------
  1600.  
  1601.    --  This dummy procedure gives us the end of the PC range for addresses
  1602.    --  within the exception unit itself. We hope that gigi/gcc keeps all the
  1603.    --  procedures in their original order!
  1604.  
  1605.    procedure ZZZ is
  1606.    begin
  1607.       null;
  1608.    end ZZZ;
  1609.  
  1610. begin
  1611.    --  Allocate the Non-Tasking Machine_State
  1612.  
  1613.    Set_Machine_State_Addr_NT (Allocate_Machine_State);
  1614. end Ada.Exceptions;
  1615.