1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- G N A T . T R A C E B A C K . S Y M B O L I C --
9 -- Copyright (C) 2005-2010, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 -- Run-time symbolic traceback support for IA64/VMS
34 with Ada
.Exceptions
.Traceback
; use Ada
.Exceptions
.Traceback
;
37 with System
.Soft_Links
;
38 with System
.Traceback_Entries
;
40 package body GNAT
.Traceback
.Symbolic
is
44 use System
.Traceback_Entries
;
46 subtype Var_String_Buf
is String (1 .. 254);
48 type Var_String
is record
49 Curlen
: Unsigned_Word
:= 0;
52 pragma Convention
(C
, Var_String
);
53 for Var_String
'Size use 8 * 256;
55 type Descriptor64
is record
57 Dtype
: Unsigned_Byte
;
58 Class
: Unsigned_Byte
;
59 Mbmo
: Unsigned_Longword
;
60 Maxstrlen
: Integer_64
;
63 pragma Convention
(C
, Descriptor64
);
65 subtype Cond_Value_Type
is Unsigned_Longword
;
67 -- TBK_API_PARAM as defined in TBKDEF
69 type Tbk_Api_Param
is record
70 Length
: Unsigned_Word
;
71 T_Type
: Unsigned_Byte
;
72 Version
: Unsigned_Byte
;
73 Reserveda
: Unsigned_Longword
;
74 Faulting_Pc
: Address
;
75 Faulting_Fp
: Address
;
76 Filename_Desc
: Address
;
77 Library_Module_Desc
: Address
;
78 Record_Number
: Address
;
80 Module_Desc
: Address
;
81 Routine_Desc
: Address
;
82 Listing_Lineno
: Address
;
84 Image_Base_Addr
: Address
;
85 Module_Base_Addr
: Address
;
88 Symbolize_Flags
: Address
;
89 Reserved0
: Unsigned_Quadword
;
90 Reserved1
: Unsigned_Quadword
;
91 Reserved2
: Unsigned_Quadword
;
93 pragma Convention
(C
, Tbk_Api_Param
);
95 K_Version
: constant Unsigned_Byte
:= 1;
96 -- Current API version
98 K_Length
: constant Unsigned_Word
:= 152;
99 -- Length of the parameter
101 pragma Compile_Time_Error
(Tbk_Api_Param
'Size = K_Length
* 8,
102 "Bad length for tbk_api_param");
105 function Symbolize
(Param
: Address
) return Cond_Value_Type
;
106 pragma Import
(C
, Symbolize
, "TBK$I64_SYMBOLIZE");
108 function Decode_Ada_Name
(Encoded_Name
: String) return String;
109 -- Decodes an Ada identifier name. Removes leading "_ada_" and trailing
110 -- __{DIGIT}+ or ${DIGIT}+, converts other "__" to '.'
112 procedure Setup_Descriptor64_Vs
(Desc
: out Descriptor64
; Var
: Address
);
113 -- Setup descriptor Desc for address Var
115 ---------------------
116 -- Decode_Ada_Name --
117 ---------------------
119 function Decode_Ada_Name
(Encoded_Name
: String) return String is
120 Decoded_Name
: String (1 .. Encoded_Name
'Length);
121 Pos
: Integer := Encoded_Name
'First;
122 Last
: Integer := Encoded_Name
'Last;
130 -- Skip leading _ada_
132 if Encoded_Name
'Length > 4
133 and then Encoded_Name
(Pos
.. Pos
+ 4) = "_ada_"
138 -- Skip trailing __{DIGIT}+ or ${DIGIT}+
140 if Encoded_Name
(Last
) in '0' .. '9' then
141 for J
in reverse Pos
+ 2 .. Last
- 1 loop
142 case Encoded_Name
(J
) is
151 if Encoded_Name
(J
- 1) = '_' then
162 -- Now just copy encoded name to decoded name, converting "__" to '.'
164 while Pos
<= Last
loop
165 if Encoded_Name
(Pos
) = '_' and then Encoded_Name
(Pos
+ 1) = '_'
166 and then Pos
/= Encoded_Name
'First
168 Decoded_Name
(DPos
) := '.';
171 Decoded_Name
(DPos
) := Encoded_Name
(Pos
);
178 return Decoded_Name
(1 .. DPos
- 1);
181 ---------------------------
182 -- Setup_Descriptor64_Vs --
183 ---------------------------
185 procedure Setup_Descriptor64_Vs
(Desc
: out Descriptor64
; Var
: Address
) is
186 K_Dtype_Vt
: constant Unsigned_Byte
:= 37;
187 K_Class_Vs
: constant Unsigned_Byte
:= 11;
190 Desc
.Dtype
:= K_Dtype_Vt
;
191 Desc
.Class
:= K_Class_Vs
;
193 Desc
.Maxstrlen
:= Integer_64
(Var_String_Buf
'Length);
195 end Setup_Descriptor64_Vs
;
197 ------------------------
198 -- Symbolic_Traceback --
199 ------------------------
201 function Symbolic_Traceback
(Traceback
: Tracebacks_Array
) return String is
202 Param
: Tbk_Api_Param
;
203 Status
: Cond_Value_Type
;
204 Record_Number
: Unsigned_Longword
;
205 Image_Name
: Var_String
;
206 Image_Dsc
: Descriptor64
;
207 Module_Name
: Var_String
;
208 Module_Dsc
: Descriptor64
;
209 Routine_Name
: Var_String
;
210 Routine_Dsc
: Descriptor64
;
211 Line_Number
: Unsigned_Longword
;
212 Res
: String (1 .. 256 * Traceback
'Length);
216 if Traceback
'Length = 0 then
222 -- Since image computation is not thread-safe we need task lockout
224 System
.Soft_Links
.Lock_Task
.all;
226 -- Initialize descriptors
228 Setup_Descriptor64_Vs
(Image_Dsc
, Image_Name
'Address);
229 Setup_Descriptor64_Vs
(Module_Dsc
, Module_Name
'Address);
230 Setup_Descriptor64_Vs
(Routine_Dsc
, Routine_Name
'Address);
232 for J
in Traceback
'Range loop
233 -- Initialize fields in case they are not written
237 Image_Name
.Curlen
:= 0;
238 Module_Name
.Curlen
:= 0;
239 Routine_Name
.Curlen
:= 0;
243 Param
:= (Length
=> K_Length
,
245 Version
=> K_Version
,
247 Faulting_Pc
=> PC_For
(Traceback
(J
)),
249 Filename_Desc
=> Null_Address
,
250 Library_Module_Desc
=> Null_Address
,
251 Record_Number
=> Record_Number
'Address,
252 Image_Desc
=> Image_Dsc
'Address,
253 Module_Desc
=> Module_Dsc
'Address,
254 Routine_Desc
=> Routine_Dsc
'Address,
255 Listing_Lineno
=> Line_Number
'Address,
256 Rel_Pc
=> Null_Address
,
257 Image_Base_Addr
=> Null_Address
,
258 Module_Base_Addr
=> Null_Address
,
259 Malloc_Rtn
=> Null_Address
,
260 Free_Rtn
=> Null_Address
,
261 Symbolize_Flags
=> Null_Address
,
264 Reserved2
=> (0, 0));
266 Status
:= Symbolize
(Param
'Address);
268 -- Check for success (marked by bit 0)
270 if (Status
rem 2) = 1 then
274 if Line_Number
= 0 then
276 -- As GCC doesn't emit source file correlation, use record
277 -- number of line number is not set
279 Line_Number
:= Record_Number
;
283 First
: constant Integer := Len
+ 1;
284 Last
: Integer := First
+ 80 - 1;
287 Routine_Name_D
: constant String :=
290 (1 .. Natural (Routine_Name
.Curlen
)));
292 Lineno
: constant String :=
293 Unsigned_Longword
'Image (Line_Number
);
296 Res
(First
.. Last
) := (others => ' ');
298 Res
(First
.. First
+ Natural (Image_Name
.Curlen
) - 1) :=
299 Image_Name
.Buf
(1 .. Natural (Image_Name
.Curlen
));
302 First
+ 10 + Natural (Module_Name
.Curlen
) - 1) :=
303 Module_Name
.Buf
(1 .. Natural (Module_Name
.Curlen
));
306 First
+ 30 + Routine_Name_D
'Length - 1) :=
309 -- If routine name doesn't fit 20 characters, output the line
310 -- number on next line at 50th position.
312 if Routine_Name_D
'Length > 20 then
313 Pos
:= First
+ 30 + Routine_Name_D
'Length;
314 Res
(Pos
) := ASCII
.LF
;
316 Res
(Pos
+ 1 .. Last
) := (others => ' ');
322 Res
(Pos
.. Pos
+ Lineno
'Length - 1) := Lineno
;
324 Res
(Last
) := ASCII
.LF
;
328 -- Failure (bit 0 clear)
331 Res
(Len
+ 1 .. Len
+ 6) := "ERROR" & ASCII
.LF
;
336 System
.Soft_Links
.Unlock_Task
.all;
337 return Res
(1 .. Len
);
338 end Symbolic_Traceback
;
340 function Symbolic_Traceback
(E
: Exception_Occurrence
) return String is
342 return Symbolic_Traceback
(Tracebacks
(E
));
343 end Symbolic_Traceback
;
345 end GNAT
.Traceback
.Symbolic
;