File : s-traceb-cert-ppc.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- S Y S T E M . T R A C E B A C K --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1999-2014, 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 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. --
17 -- --
18 -- --
19 -- --
20 -- --
21 -- --
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/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
29 -- --
30 ------------------------------------------------------------------------------
31
32 with System.Address_To_Access_Conversions;
33
34 -- The unit is a replacement of tracebak.c for PowerPC targets with
35 -- certification needs, providing an all Ada implementation with a very
36 -- simple parameterization scheme (see System.Traceback_Control below).
37
38 -- The general principle of operation is similar: assuming a simple memory
39 -- organization of the call stack frames with both a return address and a
40 -- back-link expected to be stored at a fixed offset from a given frame
41 -- pointer. For "main" calling "A" calling "B", something like:
42 --
43 -- SP <------ stack memory, frames push this way TOP
44 -- | <------ (decreasing addresses) on calls |
45 -- v v
46 -- |<----- frame for B ----->|<----- frame for A ----->|< frame for main >|
47 -- . . . .
48 -- . ------------------------ ------------------------ .
49 -- . | . v | . v .
50 -- #====|====================#====|====================#==================#
51 -- # link | ... | ret@ | ... # link | ... | ret@ | ... # link ... #
52 -- #===============|=========#===============|=========#==================#
53 -- . v . v . .
54 -- . 1 insn past the . 1 insn past the . .
55 -- . call to B in A . call to A in main . .
56
57 -- Computing a backtrace consists in walking up the link chains starting from
58 -- the current frame, latching the address of calls at each step and stopping
59 -- when the top frame is reached.
60
61 -- This is pretty much generic except for two ABI details that vary across
62 -- OS implementations: the frame pointer to return address offset, and
63 -- the characterization of the top-of-stack frame. We rely on a separate
64 -- Traceback_Control package to expose a consistent abstraction of those
65 -- differences.
66
67 with System.Traceback_Control; use System.Traceback_Control;
68
69 -- We expect Traceback_Control to expose:
70 --
71 -- function Return_Address_Offset return System.Address;
72 -- -- Relative to a given frame pointer, the constant offset at which the
73 -- -- return address for this frame is stored.
74 --
75 -- FP RA_Offset
76 -- |----------->|
77 -- v v
78 -- #=====================...
79 -- # link | ... | ret@ | ...
80 -- #=====================...
81 --
82 -- Then:
83 --
84 -- function Is_Topframe_Retaddr (Retaddr : System.Address) return boolean;
85 -- -- Whether the provided Retaddr signals a top-of-stack frame.
86
87 package body System.Traceback is
88
89 package Addr is new System.Address_To_Access_Conversions (System.Address);
90
91 package CTL renames System.Traceback_Control;
92
93 -----------------
94 -- Frame links --
95 -----------------
96
97 function Link_From (Frame : System.Address) return System.Address;
98 -- For a given subprogram frame, return the address of the next
99 -- frame in the call chain.
100
101 pragma Inline (Link_From);
102
103 function Link_From (Frame : System.Address) return System.Address is
104
105 Frame_Link_Offset : constant := 0;
106 -- Relative to a given frame pointer, this is the offset in bytes of
107 -- the memory location where we always expect the address of the caller
108 -- frame to be stored. This defines our notion of a frame pointer.
109
110 begin
111 return Addr.To_Pointer (Frame + Frame_Link_Offset).all;
112 end Link_From;
113
114 ---------------
115 -- Frame PCs --
116 ---------------
117
118 function Retaddr_From (Frame : System.Address) return System.Address;
119 -- Return the return address for a given frame
120
121 pragma Inline (Retaddr_From);
122
123 function Retaddr_From (Frame : System.Address) return System.Address is
124 begin
125 -- Here, the offset at which we expect to find the return address
126 -- in the frame is part of control parameters.
127
128 return Addr.To_Pointer (Frame + CTL.Return_Address_Offset).all;
129 end Retaddr_From;
130
131 ----------------------------------
132 -- Identifying the Top of stack --
133 ----------------------------------
134
135 function Top_Of_Stack_At (Frame : System.Address) return Boolean;
136 -- Whether the provided Frame pointer designates a call chain entry point.
137
138 pragma Inline (Top_Of_Stack_At);
139
140 function Top_Of_Stack_At (Frame : System.Address) return Boolean is
141 begin
142 -- Two indicators we expect are a null frame pointer (back-link from
143 -- the previous frame) or a particular return address with variations
144 -- across target ABIs. We add an extra alignment check only to prevent
145 -- erroneous memory accesses in case something unexpected happens.
146
147 return Frame = System.Null_Address
148 or else Frame mod System.Address'Alignment /= 0
149 or else CTL.Is_Topframe_Retaddr (Retaddr_From (Frame));
150 end Top_Of_Stack_At;
151
152 ------------------
153 -- Call_Chain --
154 ------------------
155
156 procedure Call_Chain
157 (Traceback : in out System.Traceback_Entries.Tracebacks_Array;
158 Max_Len : Natural;
159 Len : out Natural;
160 Exclude_Min : System.Address := System.Null_Address;
161 Exclude_Max : System.Address := System.Null_Address;
162 Skip_Frames : Natural := 1) is
163
164 pragma Assert (Return_Address_Offset mod System.Address'Alignment = 0);
165
166 Retaddr_To_Call_Offset : constant := 4;
167 -- Size of call instruction to subtract from return address to get the
168 -- PC of the corresponding call instruction.
169
170 Frame : System.Address;
171 -- Frame being processed
172
173 Last : Integer := Traceback'First - 1;
174 -- Index of last traceback written to the buffer
175
176 procedure Forced_Callee;
177 -- Force save of return address of Call_Chain on PPC
178
179 -------------------
180 -- Forced_Callee --
181 -------------------
182
183 -- The PPC ABI has an unusual characteristic: the return address saved
184 -- by a subprogram is located in its caller's frame, and the save
185 -- operation only occurs if the function performs a call.
186
187 -- To make Call_Chain able to consistently retrieve its own return
188 -- address, we define Forced_Callee and call it. This routine should
189 -- never be inlined.
190
191 procedure Forced_Callee is
192 Dummy : aliased Integer := 0;
193 pragma Volatile (Dummy);
194 pragma Warnings (Off, Dummy);
195 -- Force allocation of a frame. Dummy must be both volatile and
196 -- referenced (achieved by declaring it aliased). Suppress warning
197 -- that it could be declared a constant, and that pragma Volatile
198 -- has no effect (it forces creation of the frame).
199 begin
200 null;
201 end Forced_Callee;
202
203 function builtin_frame_address (Level : Integer) return System.Address;
204 pragma Import
205 (Intrinsic, builtin_frame_address, "__builtin_frame_address");
206
207 -- Start of processing for Call_Chain
208
209 begin
210 Forced_Callee;
211 Len := 0;
212
213 -- Start with the frame pointer for the current frame.
214
215 Frame := builtin_frame_address (0);
216
217 -- Skip the first Skip_Frames frames, as required by our spec. If we
218 -- happen to hit the top of stack while doing so, just yield an empty
219 -- trace. We expect this never to happen in regular circumstances of
220 -- calls issued by the other parts of the runtime library.
221
222 for J in 1 .. Skip_Frames + 1 loop
223 if Top_Of_Stack_At (Frame) then
224 return;
225 end if;
226
227 Frame := Link_From (Frame);
228 end loop;
229
230 pragma Assert (Frame /= System.Null_Address);
231
232 -- Now walk up recording call addresses as we go. Stop when the top
233 -- of stack is reached or when the provided trace buffer is full.
234 -- Don't record addresses in the provided exclusion range, typically
235 -- used to leave aside frames from our exception propagation internals.
236
237 while not Top_Of_Stack_At (Frame)
238 and then Last < Traceback'Last
239 and then Len < Max_Len
240 loop
241
242 declare
243 Call_Addr : constant System.Address
244 := Retaddr_From (Frame) - Retaddr_To_Call_Offset;
245
246 begin
247 if Call_Addr not in Exclude_Min .. Exclude_Max then
248 Last := Last + 1;
249 Len := Len + 1;
250 Traceback (Last) := Call_Addr;
251 end if;
252
253 Frame := Link_From (Frame);
254 end;
255
256 pragma Assert (Frame /= System.Null_Address);
257 end loop;
258 end Call_Chain;
259
260 end System.Traceback;