* configure.ac: Don't test for [build] __cxa_atexit when building a
[official-gcc.git] / gcc / ada / vxaddr2line.adb
blob5fc7759276f2dbbba13a4566c20cfc127f216699
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- V X A D D R 2 L I N E --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2002-2003 Ada Core Technologies, 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 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 -- --
25 ------------------------------------------------------------------------------
27 -- This program is meant to be used with vxworks to compute symbolic
28 -- backtraces on the host from non-symbolic backtraces obtained on the target.
30 -- The basic idea is to automate the computation of the necessary address
31 -- adjustments prior to calling addr2line when the application has only been
32 -- partially linked on the host.
34 -- Variants for various targets are supported, and the command line should
35 -- be like :
37 -- <target>-addr2line [-a <target_arch>] <exe_file> <ref_address>
38 -- <backtrace addresses>
40 -- Where:
41 -- <target_arch> :
42 -- selects the target architecture. In the absence of this parameter the
43 -- default variant is chosen based on the Detect_Arch result. Generally,
44 -- this parameter will only be used if vxaddr2line is recompiled manually.
45 -- Otherwise, the command name will always be of the form
46 -- <target>-vxaddr2line where there is no ambiguity on the target's
47 -- architecture.
49 -- <exe_file> :
50 -- The name of the partially linked binary file for the application.
52 -- <ref_address> :
53 -- Runtime address (on the target) of a reference symbol you choose,
54 -- which name shall match the value of the Ref_Symbol variable declared
55 -- below. A symbol with a small offset from the beginning of the text
56 -- segment is better, so "adainit" is a good choice.
58 -- <backtrace addresses> :
59 -- The call chain addresses you obtained at run time on the target and
60 -- for which you want a symbolic association.
62 -- TO ADD A NEW ARCHITECTURE add an appropriate value to Architecture type
63 -- (in a format <host>_<target>), and then an appropriate value to Config_List
64 -- array
66 with Text_IO; use Text_IO;
67 with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
68 with Ada.Command_Line; use Ada.Command_Line;
69 with Ada.Strings.Fixed; use Ada.Strings.Fixed;
71 with GNAT.OS_Lib; use GNAT.OS_Lib;
72 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
73 with GNAT.Expect; use GNAT.Expect;
74 with GNAT.Regpat; use GNAT.Regpat;
76 procedure VxAddr2Line is
78 Ref_Symbol : constant String := "adainit";
79 -- This is the name of the reference symbol which runtime address shall
80 -- be provided as the <ref_address> argument.
82 -- All supported architectures
83 type Architecture is
84 (WINDOWS_POWERPC,
85 WINDOWS_M68K,
86 SOLARIS_POWERPC,
87 DEC_ALPHA);
89 type Arch_Record is record
90 Addr2line_Binary : String_Access;
91 -- Name of the addr2line utility to use.
93 Nm_Binary : String_Access;
94 -- Name of the host nm utility, which will be used to find out the
95 -- offset of the reference symbol in the text segment of the partially
96 -- linked executable.
98 Addr_Digits_To_Skip : Integer;
99 -- When addresses such as 0xfffffc0001dfed50 are provided, for instance
100 -- on ALPHA, indicate the number of leading digits that can be ignored,
101 -- which will avoid computational overflows. Typically only useful when
102 -- 64bit addresses are provided.
104 Bt_Offset_From_Call : Integer;
105 -- Offset from a backtrace address to the address of the corresponding
106 -- call instruction. This should always be 0, except on platforms where
107 -- the backtrace addresses actually correspond to return and not call
108 -- points. In such cases, a negative value is most likely.
109 end record;
111 -- Configuration for each of the architectures
112 Arch_List : array (Architecture'Range) of Arch_Record :=
113 (WINDOWS_POWERPC =>
114 (Addr2line_Binary => null,
115 Nm_Binary => null,
116 Addr_Digits_To_Skip => 0,
117 Bt_Offset_From_Call => -4),
118 WINDOWS_M68K =>
119 (Addr2line_Binary => null,
120 Nm_Binary => null,
121 Addr_Digits_To_Skip => 0,
122 Bt_Offset_From_Call => -4),
123 SOLARIS_POWERPC =>
124 (Addr2line_Binary => null,
125 Nm_Binary => null,
126 Addr_Digits_To_Skip => 0,
127 Bt_Offset_From_Call => 0),
128 DEC_ALPHA =>
129 (Addr2line_Binary => null,
130 Nm_Binary => null,
131 Addr_Digits_To_Skip => 8,
132 Bt_Offset_From_Call => 0)
135 -- Current architecture
136 Cur_Arch : Architecture;
138 -- State of architecture detection
139 Detect_Success : Boolean := False;
141 -----------------------
142 -- Local subprograms --
143 -----------------------
145 procedure Error (Msg : String);
146 pragma No_Return (Error);
147 -- Prints the message and then terminates the program
149 procedure Usage;
150 -- Displays the short help message and then terminates the program
152 function Get_Reference_Offset return Integer;
153 -- Computes the static offset of the reference symbol by calling nm
155 function Get_Value_From_Hex_Arg (Arg : Natural) return Integer;
156 -- Threats the argument number Arg as a C-style hexadecimal literal
157 -- and returns its integer value
159 function Hex_Image (Value : Integer) return String_Access;
160 -- Returns access to a string that contains hexadecimal image of Value
162 -- Separate functions that provide build-time customization:
164 procedure Detect_Arch;
165 -- Saves in Cur_Arch the current architecture, based on the name of
166 -- vxaddr2line instance and properties of the host. Detect_Success is False
167 -- if detection fails
169 -----------------
170 -- Detect_Arch --
171 -----------------
173 procedure Detect_Arch is
174 Name : constant String := Base_Name (Command_Name);
175 Proc : constant String :=
176 Name (Name'First .. Index (Name, "-") - 1);
177 Target : constant String :=
178 Name (Name'First .. Index (Name, "vxaddr2line") - 1);
180 begin
181 Detect_Success := False;
183 if Proc = "" then
184 return;
185 end if;
187 if Proc = "alpha" then
188 Cur_Arch := DEC_ALPHA;
189 else
190 -- Let's detect the host.
191 -- ??? A naive implementation that can't distinguish between Unixes
192 if Directory_Separator = '/' then
193 Cur_Arch := Architecture'Value ("solaris_" & Proc);
194 else
195 Cur_Arch := Architecture'Value ("windows_" & Proc);
196 end if;
197 end if;
199 if Arch_List (Cur_Arch).Addr2line_Binary = null then
200 Arch_List (Cur_Arch).Addr2line_Binary := new String'
201 (Target & "addr2line");
202 end if;
203 if Arch_List (Cur_Arch).Nm_Binary = null then
204 Arch_List (Cur_Arch).Nm_Binary := new String'
205 (Target & "nm");
206 end if;
208 Detect_Success := True;
210 exception
211 when others =>
212 return;
213 end Detect_Arch;
216 -----------
217 -- Error --
218 -----------
220 procedure Error (Msg : String) is
221 begin
222 Put_Line (Msg);
223 OS_Exit (1);
224 raise Program_Error;
225 end Error;
228 --------------------------
229 -- Get_Reference_Offset --
230 --------------------------
232 function Get_Reference_Offset return Integer is
233 Nm_Cmd : constant String_Access :=
234 Locate_Exec_On_Path (Arch_List (Cur_Arch).Nm_Binary.all);
236 Nm_Args : constant Argument_List :=
237 (new String'("-P"),
238 new String'(Argument (1)));
240 Forever : aliased String := "^@@@@";
241 Reference : aliased String := Ref_Symbol & "\s+\S\s+([\da-fA-F]+)";
243 Pd : Process_Descriptor;
244 Result : Expect_Match;
246 begin
247 -- If Nm is not found, abort
249 if Nm_Cmd = null then
250 Error ("Couldn't find " & Arch_List (Cur_Arch).Nm_Binary.all);
251 end if;
253 Non_Blocking_Spawn
254 (Pd, Nm_Cmd.all, Nm_Args, Buffer_Size => 0, Err_To_Out => True);
256 -- Expect a string containing the reference symbol
258 Expect (Pd, Result,
259 Regexp_Array'(1 => Reference'Unchecked_Access),
260 Timeout => -1);
262 -- If we are here, the pattern was matched successfully
264 declare
265 Match_String : constant String := Expect_Out_Match (Pd);
266 Matches : Match_Array (0 .. 1);
267 Value : Integer;
269 begin
270 Match (Reference, Match_String, Matches);
271 Value := Integer'Value
272 ("16#"
273 & Match_String (Matches (1).First .. Matches (1).Last) & "#");
275 -- Expect a string that will never be emitted, so that the
276 -- process can be correctly terminated (with Process_Died)
278 Expect (Pd, Result,
279 Regexp_Array'(1 => Forever'Unchecked_Access),
280 Timeout => -1);
282 exception
283 when Process_Died =>
284 return Value;
285 end;
287 -- We can not get here
289 raise Program_Error;
291 exception
292 when Invalid_Process =>
293 Error ("Could not spawn a process " & Nm_Cmd.all);
295 when others =>
297 -- The process died without matching the reference symbol or the
298 -- format wasn't recognized.
300 Error ("Unexpected output from " & Nm_Cmd.all);
301 end Get_Reference_Offset;
303 ----------------------------
304 -- Get_Value_From_Hex_Arg --
305 ----------------------------
307 function Get_Value_From_Hex_Arg (Arg : Natural) return Integer is
308 Cur_Arg : constant String := Argument (Arg);
309 Offset : Natural;
311 begin
312 -- Skip "0x" prefix if present
314 if Cur_Arg'Length > 2 and then Cur_Arg (1 .. 2) = "0x" then
315 Offset := 3;
316 else
317 Offset := 1;
318 end if;
320 -- Add architecture-specific offset
322 Offset := Offset + Arch_List (Cur_Arch).Addr_Digits_To_Skip;
324 -- Convert to value
326 return Integer'Value ("16#" & Cur_Arg (Offset .. Cur_Arg'Last) & "#");
327 end Get_Value_From_Hex_Arg;
329 ---------------
330 -- Hex_Image --
331 ---------------
333 function Hex_Image (Value : Integer) return String_Access is
334 Result : String (1 .. 20);
335 Start_Pos : Natural;
337 begin
338 Put (Result, Value, 16);
339 Start_Pos := Index (Result, "16#") + 3;
340 return new String'(Result (Start_Pos .. Result'Last - 1));
341 end Hex_Image;
343 -----------
344 -- Usage --
345 -----------
347 procedure Usage is
348 begin
349 Put_Line ("Usage : " & Base_Name (Command_Name)
350 & " <executable> <"
351 & Ref_Symbol & " offset on target> <addr1> ...");
353 OS_Exit (1);
354 end Usage;
356 Ref_Static_Offset, Ref_Runtime_Address, Bt_Address : Integer;
358 Addr2line_Cmd : String_Access;
360 Addr2line_Args : Argument_List (1 .. 501);
361 -- We expect that there won't be more than 500 backtrace frames
363 Addr2line_Args_Count : Natural;
365 Success : Boolean;
367 -- Start of processing for VxAddr2Line
369 begin
371 Detect_Arch;
373 -- There should be at least two arguments
375 if Argument_Count < 2 then
376 Usage;
377 end if;
379 -- ??? HARD LIMIT! There should be at most 501 arguments
381 if Argument_Count > 501 then
382 Error ("Too many backtrace frames");
383 end if;
385 -- Do we have a valid architecture?
387 if not Detect_Success then
388 Put_Line ("Couldn't detect the architecture");
389 return;
390 end if;
392 Addr2line_Cmd :=
393 Locate_Exec_On_Path (Arch_List (Cur_Arch).Addr2line_Binary.all);
395 -- If Addr2line is not found, abort
397 if Addr2line_Cmd = null then
398 Error ("Couldn't find " & Arch_List (Cur_Arch).Addr2line_Binary.all);
399 end if;
401 -- The first argument specifies the image file. Check if it exists.
403 if not Is_Regular_File (Argument (1)) then
404 Error ("Couldn't find the executable " & Argument (1));
405 end if;
407 -- The second argument specifies the reference symbol runtime address.
408 -- Let's parse and store it
410 Ref_Runtime_Address := Get_Value_From_Hex_Arg (2);
412 -- Run nm command to get the reference symbol static offset
414 Ref_Static_Offset := Get_Reference_Offset;
416 -- Build addr2line parameters. First, the standard part
418 Addr2line_Args (1) := new String'("--exe=" & Argument (1));
419 Addr2line_Args_Count := 1;
421 -- Now, append to this the adjusted backtraces in arguments 4 and further
423 for J in 3 .. Argument_Count loop
425 -- Basically, for each address in the runtime backtrace ...
427 -- o We compute its offset relatively to the runtime address of the
428 -- reference symbol,
430 -- and then ...
432 -- o We add this offset to the static one for the reference symbol in
433 -- the executable to find the executable offset corresponding to the
434 -- backtrace address.
436 Bt_Address := Get_Value_From_Hex_Arg (J);
438 Bt_Address :=
439 Bt_Address - Ref_Runtime_Address
440 + Ref_Static_Offset
441 + Arch_List (Cur_Arch).Bt_Offset_From_Call;
443 Addr2line_Args_Count := Addr2line_Args_Count + 1;
444 Addr2line_Args (Addr2line_Args_Count) := Hex_Image (Bt_Address);
445 end loop;
447 -- Run the resulting command
449 Spawn (Addr2line_Cmd.all,
450 Addr2line_Args (1 .. Addr2line_Args_Count), Success);
452 exception
453 when others =>
455 -- Mask all exceptions
457 return;
458 end VxAddr2Line;