OSDN Git Service

* config/vax/vax.h (target_flags, MASK_UNIX_ASM, MASK_VAXC_ALIGNMENT)
[pf3gnuchains/gcc-fork.git] / gcc / ada / g-trasym-vms.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT RUN-TIME COMPONENTS                         --
4 --                                                                          --
5 --             G N A T . T R A C E B A C K . S Y M B O L I C                --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --           Copyright (C) 1999-2003 Free Software Foundation, Inc.         --
10 --                                                                          --
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.                                                      --
21 --                                                                          --
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.                                      --
28 --                                                                          --
29 -- GNAT was originally developed  by the GNAT team at  New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 --  Run-time symbolic traceback support for VMS
35
36 with Ada.Exceptions.Traceback; use Ada.Exceptions.Traceback;
37 with Interfaces.C;
38 with System;
39 with System.Aux_DEC;
40 with System.Soft_Links;
41 with System.Traceback_Entries;
42
43 package body GNAT.Traceback.Symbolic is
44
45    pragma Warnings (Off);
46    pragma Linker_Options ("--for-linker=sys$library:trace.exe");
47
48    use Interfaces.C;
49    use System;
50    use System.Aux_DEC;
51    use System.Traceback_Entries;
52
53    subtype User_Arg_Type is Unsigned_Longword;
54    subtype Cond_Value_Type is Unsigned_Longword;
55
56    type ASCIC is record
57       Count : unsigned_char;
58       Data  : char_array (1 .. 255);
59    end record;
60    pragma Convention (C, ASCIC);
61
62    for ASCIC use record
63       Count at 0 range 0 .. 7;
64       Data  at 1 range 0 .. 8 * 255 - 1;
65    end record;
66    for ASCIC'Size use 8 * 256;
67
68    function Fetch_ASCIC is new Fetch_From_Address (ASCIC);
69
70    procedure Symbolize
71      (Status         : out Cond_Value_Type;
72       Current_PC     : in Address;
73       Adjusted_PC    : in Address;
74       Current_FP     : in Address;
75       Current_R26    : in Address;
76       Image_Name     : out Address;
77       Module_Name    : out Address;
78       Routine_Name   : out Address;
79       Line_Number    : out Integer;
80       Relative_PC    : out Address;
81       Absolute_PC    : out Address;
82       PC_Is_Valid    : out Long_Integer;
83       User_Act_Proc  : Address           := Address'Null_Parameter;
84       User_Arg_Value : User_Arg_Type     := User_Arg_Type'Null_Parameter);
85
86    pragma Interface (External, Symbolize);
87
88    pragma Import_Valued_Procedure
89      (Symbolize, "TBK$SYMBOLIZE",
90       (Cond_Value_Type, Address, Address, Address, Address,
91        Address, Address, Address, Integer,
92        Address, Address, Long_Integer,
93        Address, User_Arg_Type),
94       (Value, Value, Value, Value, Value,
95        Reference, Reference, Reference, Reference,
96        Reference, Reference, Reference,
97        Value, Value),
98        User_Act_Proc);
99
100    function Decode_Ada_Name (Encoded_Name : String) return String;
101    --  Decodes an Ada identifier name. Removes leading "_ada_" and trailing
102    --  __{DIGIT}+ or ${DIGIT}+, converts other "__" to '.'
103
104    ---------------------
105    -- Decode_Ada_Name --
106    ---------------------
107
108    function Decode_Ada_Name (Encoded_Name : String) return String is
109       Decoded_Name : String (1 .. Encoded_Name'Length);
110       Pos          : Integer := Encoded_Name'First;
111       Last         : Integer := Encoded_Name'Last;
112       DPos         : Integer := 1;
113
114    begin
115       if Pos > Last then
116          return "";
117       end if;
118
119       --  Skip leading _ada_
120
121       if Encoded_Name'Length > 4
122         and then Encoded_Name (Pos .. Pos + 4) = "_ada_"
123       then
124          Pos := Pos + 5;
125       end if;
126
127       --  Skip trailing __{DIGIT}+ or ${DIGIT}+
128
129       if Encoded_Name (Last) in '0' .. '9' then
130          for J in reverse Pos + 2 .. Last - 1 loop
131             case Encoded_Name (J) is
132                when '0' .. '9' =>
133                   null;
134                when '$' =>
135                   Last := J - 1;
136                   exit;
137                when '_' =>
138                   if Encoded_Name (J - 1) = '_' then
139                      Last := J - 2;
140                   end if;
141                   exit;
142                when others =>
143                   exit;
144             end case;
145          end loop;
146       end if;
147
148       --  Now just copy encoded name to decoded name, converting "__" to '.'
149
150       while Pos <= Last loop
151          if Encoded_Name (Pos) = '_' and then Encoded_Name (Pos + 1) = '_'
152            and then Pos /= Encoded_Name'First
153          then
154             Decoded_Name (DPos) := '.';
155             Pos := Pos + 2;
156
157          else
158             Decoded_Name (DPos) := Encoded_Name (Pos);
159             Pos := Pos + 1;
160          end if;
161
162          DPos := DPos + 1;
163       end loop;
164
165       return Decoded_Name (1 .. DPos - 1);
166    end Decode_Ada_Name;
167
168    ------------------------
169    -- Symbolic_Traceback --
170    ------------------------
171
172    function Symbolic_Traceback (Traceback : Tracebacks_Array) return String is
173       Status            : Cond_Value_Type;
174       Image_Name        : ASCIC;
175       Image_Name_Addr   : Address;
176       Module_Name       : ASCIC;
177       Module_Name_Addr  : Address;
178       Routine_Name      : ASCIC;
179       Routine_Name_Addr : Address;
180       Line_Number       : Integer;
181       Relative_PC       : Address;
182       Absolute_PC       : Address;
183       PC_Is_Valid       : Long_Integer;
184       Return_Address    : Address;
185       Res               : String (1 .. 256 * Traceback'Length);
186       Len               : Integer;
187
188    begin
189       if Traceback'Length > 0 then
190          Len := 0;
191
192          --  Since image computation is not thread-safe we need task lockout
193
194          System.Soft_Links.Lock_Task.all;
195
196          for J in Traceback'Range loop
197             if J = Traceback'Last then
198                Return_Address := Address_Zero;
199             else
200                Return_Address := PC_For (Traceback (J + 1));
201             end if;
202
203             Symbolize
204               (Status,
205                PC_For (Traceback (J)),
206                PC_For (Traceback (J)),
207                PV_For (Traceback (J)),
208                Return_Address,
209                Image_Name_Addr,
210                Module_Name_Addr,
211                Routine_Name_Addr,
212                Line_Number,
213                Relative_PC,
214                Absolute_PC,
215                PC_Is_Valid);
216
217             Image_Name   := Fetch_ASCIC (Image_Name_Addr);
218             Module_Name  := Fetch_ASCIC (Module_Name_Addr);
219             Routine_Name := Fetch_ASCIC (Routine_Name_Addr);
220
221             declare
222                First : Integer := Len + 1;
223                Last  : Integer := First + 80 - 1;
224                Pos   : Integer;
225                Routine_Name_D : String := Decode_Ada_Name
226                  (To_Ada
227                     (Routine_Name.Data (1 .. size_t (Routine_Name.Count)),
228                      False));
229
230             begin
231                Res (First .. Last) := (others => ' ');
232
233                Res (First .. First + Integer (Image_Name.Count) - 1) :=
234                  To_Ada
235                   (Image_Name.Data (1 .. size_t (Image_Name.Count)),
236                    False);
237
238                Res (First + 10 ..
239                     First + 10 + Integer (Module_Name.Count) - 1) :=
240                  To_Ada
241                   (Module_Name.Data (1 .. size_t (Module_Name.Count)),
242                    False);
243
244                Res (First + 30 ..
245                     First + 30 + Routine_Name_D'Length - 1) :=
246                  Routine_Name_D;
247
248                --  If routine name doesn't fit 20 characters, output
249                --  the line number on next line at 50th position
250
251                if Routine_Name_D'Length > 20 then
252                   Pos := First + 30 + Routine_Name_D'Length;
253                   Res (Pos) := ASCII.LF;
254                   Last := Pos + 80;
255                   Res (Pos + 1 .. Last) := (others => ' ');
256                   Pos := Pos + 51;
257                else
258                   Pos := First + 50;
259                end if;
260
261                Res (Pos .. Pos + Integer'Image (Line_Number)'Length - 1) :=
262                  Integer'Image (Line_Number);
263
264                Res (Last) := ASCII.LF;
265                Len := Last;
266             end;
267          end loop;
268
269          System.Soft_Links.Unlock_Task.all;
270          return Res (1 .. Len);
271
272       else
273          return "";
274       end if;
275    end Symbolic_Traceback;
276
277    function Symbolic_Traceback (E : Exception_Occurrence) return String is
278    begin
279       return Symbolic_Traceback (Tracebacks (E));
280    end Symbolic_Traceback;
281
282 end GNAT.Traceback.Symbolic;