xref: /trunk/main/sal/osl/unx/backtrace.c (revision 9204bf8294f34a46abdfeceee27c48e7b7b2ef12)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "sal/types.h"
25 
26 
27 #ifdef SOLARIS
28 
29 #include <dlfcn.h>
30 #include <pthread.h>
31 #include <setjmp.h>
32 #include <stdio.h>
33 #include <sys/frame.h>
34 #include "backtrace.h"
35 
36 #if defined(SPARC)
37 
38 #if defined IS_LP64
39 
40 #define FRAME_PTR_OFFSET 1
41 #define FRAME_OFFSET     0
42 #define STACK_BIAS       0x7ff
43 
44 #else
45 
46 #define FRAME_PTR_OFFSET 1
47 #define FRAME_OFFSET     0
48 #define STACK_BIAS       0
49 
50 #endif
51 
52 #elif defined( INTEL )
53 
54 #define FRAME_PTR_OFFSET 3
55 #define FRAME_OFFSET     0
56 #define STACK_BIAS       0
57 
58 #else
59 
60 #error Unknown Solaris target platform.
61 
62 #endif /* defined SPARC or INTEL */
63 
64 
65 int backtrace( void **buffer, int max_frames )
66 {
67     jmp_buf       ctx;
68     long          fpval;
69     struct frame *fp;
70     int i;
71 
72     /* flush register windows */
73 #ifdef SPARC
74     asm("ta 3");
75 #endif
76 
77     /* get stack- and framepointer */
78     setjmp(ctx);
79 
80     fpval = ((long*)(ctx))[FRAME_PTR_OFFSET];
81     fp = (struct frame*)((char*)(fpval) + STACK_BIAS);
82 
83     for (i = 0; (i < FRAME_OFFSET) && (fp != NULL); i++)
84         fp = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS);
85 
86     /* iterate through backtrace */
87     for (i = 0; (fp != NULL) && (fp->fr_savpc != 0) && (i < max_frames); i++)
88     {
89         /* saved (prev) frame */
90         struct frame * prev = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS);
91 
92         /* store frame */
93         *(buffer++) = (void*)(fp->fr_savpc);
94 
95         /* prev frame (w/ stack growing top down) */
96         fp = (prev > fp) ? prev : 0;
97     }
98 
99     /* return number of frames stored */
100     return i;
101 }
102 
103 void backtrace_symbols_fd( void **buffer, int size, int fd )
104 {
105     FILE    *fp = fdopen( fd, "w" );
106 
107     if ( fp )
108     {
109         void **pFramePtr;
110 
111         for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- )
112         {
113             Dl_info     dli;
114             ptrdiff_t   offset;
115 
116             if ( 0 != dladdr( *pFramePtr, &dli ) )
117             {
118                 if ( dli.dli_fname && dli.dli_fbase )
119                 {
120                     offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase;
121                     fprintf( fp, "%s+0x%" SAL_PRI_PTRDIFFT "x", dli.dli_fname, offset );
122                 }
123                 if ( dli.dli_sname && dli.dli_saddr )
124                 {
125                     offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr;
126                     fprintf( fp, "(%s+0x%" SAL_PRI_PTRDIFFT "x)", dli.dli_sname, offset );
127                 }
128             }
129             fprintf( fp, "[%p]\n", *pFramePtr );
130         }
131 
132         fflush( fp );
133         fclose( fp );
134     }
135 }
136 
137 #endif /* defined SOLARIS */
138 
139 
140 #if defined FREEBSD || defined NETBSD
141 #include <dlfcn.h>
142 #include <pthread.h>
143 #include <setjmp.h>
144 #include <stddef.h>
145 #include <stdio.h>
146 #include "backtrace.h"
147 
148 #define FRAME_PTR_OFFSET 3
149 #define FRAME_OFFSET 0
150 
151 int backtrace( void **buffer, int max_frames )
152 {
153     struct frame *fp;
154     jmp_buf ctx;
155     int i;
156     /* get stack- and framepointer */
157     setjmp(ctx);
158     fp = (struct frame*)(((size_t*)(ctx))[FRAME_PTR_OFFSET]);
159     for ( i=0; (i<FRAME_OFFSET) && (fp!=NULL); i++)
160         fp = fp->fr_savfp;
161     /* iterate through backtrace */
162     for (i=0; fp && fp->fr_savpc && i<max_frames; i++)
163     {
164         /* store frame */
165         *(buffer++) = (void *)fp->fr_savpc;
166         /* next frame */
167         fp=fp->fr_savfp;
168     }
169     return i;
170 }
171 
172 void backtrace_symbols_fd( void **buffer, int size, int fd )
173 {
174     FILE    *fp = fdopen( fd, "w" );
175 
176     if ( fp )
177     {
178         void **pFramePtr;
179         for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- )
180         {
181             Dl_info     dli;
182             ptrdiff_t   offset;
183 
184             if ( 0 != dladdr( *pFramePtr, &dli ) )
185             {
186                 if ( dli.dli_fname && dli.dli_fbase )
187                 {
188                     offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase;
189                     fprintf( fp, "%s+0x%" SAL_PRI_PTRDIFFT "x", dli.dli_fname, offset );
190                 }
191                 if ( dli.dli_sname && dli.dli_saddr )
192                 {
193                     offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr;
194                     fprintf( fp, "(%s+0x%" SAL_PRI_PTRDIFFT "x)", dli.dli_sname, offset );
195                 }
196             }
197             fprintf( fp, "[%p]\n", *pFramePtr );
198         }
199         fflush( fp );
200         fclose( fp );
201     }
202 }
203 #endif /* defined FREEBSD */
204 
205 #ifdef LINUX
206 
207 #ifndef _GNU_SOURCE
208 #define _GNU_SOURCE
209 #endif
210 
211 #include <dlfcn.h>
212 #include <pthread.h>
213 #include <setjmp.h>
214 #include <stdio.h>
215 #include "backtrace.h"
216 
217 #if defined(SPARC)
218 
219 #define FRAME_PTR_OFFSET 1
220 #define FRAME_OFFSET 0
221 
222 #else
223 
224 #error Unknown Linux target platform.
225 
226 #endif /* defined SPARC or INTEL */
227 
228 typedef int ptrdiff_t;
229 
230 int backtrace( void **buffer, int max_frames )
231 {
232     struct frame *fp;
233     jmp_buf ctx;
234     int i;
235 
236     /* flush register windows */
237 #ifdef SPARC
238     asm("ta 3");
239 #endif
240     /* get stack- and framepointer */
241     setjmp(ctx);
242     fp = (struct frame*)(((size_t*)(ctx))[FRAME_PTR_OFFSET]);
243     for ( i=0; (i<FRAME_OFFSET) && (fp!=NULL); i++)
244         fp = fp->fr_savfp;
245 
246     /* iterate through backtrace */
247     for (i=0; fp && fp->fr_savpc && i<max_frames; i++)
248     {
249         /* store frame */
250         *(buffer++) = (void *)fp->fr_savpc;
251         /* next frame */
252         fp=fp->fr_savfp;
253     }
254     return i;
255 }
256 
257 void backtrace_symbols_fd( void **buffer, int size, int fd )
258 {
259     FILE    *fp = fdopen( fd, "w" );
260 
261     if ( fp )
262     {
263         void **pFramePtr;
264 
265         for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- )
266         {
267             Dl_info     dli;
268             ptrdiff_t   offset;
269 
270             if ( 0 != dladdr( *pFramePtr, &dli ) )
271             {
272                 if ( dli.dli_fname && dli.dli_fbase )
273                 {
274                     offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase;
275                     fprintf( fp, "%s+0x%" SAL_PRI_PTRDIFFT "x", dli.dli_fname, offset );
276                 }
277                 if ( dli.dli_sname && dli.dli_saddr )
278                 {
279                     offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr;
280                     fprintf( fp, "(%s+0x%" SAL_PRI_PTRDIFFT "x)", dli.dli_sname, offset );
281                 }
282             }
283             fprintf( fp, "[%p]\n", *pFramePtr );
284         }
285 
286         fflush( fp );
287         fclose( fp );
288     }
289 }
290 
291 #endif /* defined LINUX */
292 
293 #if defined( MACOSX )
294 
295 #include <dlfcn.h>
296 #include <stdio.h>
297 #include "backtrace.h"
298 
299 typedef unsigned     ptrdiff_t;
300 
301 /* glib backtrace is only available on MacOsX 10.5 or higher
302    so we do it on our own */
303 
304 int backtrace( void **buffer, int max_frames )
305 {
306     void **frame = (void **)__builtin_frame_address(0);
307     void **bp = ( void **)(*frame);
308     void *ip = frame[1];
309     int i;
310 
311     for ( i = 0; bp && ip && i < max_frames; i++ )
312     {
313         *(buffer++) = ip;
314 
315         ip = bp[1];
316         bp = (void**)(bp[0]);
317     }
318 
319     return i;
320 }
321 
322 
323 void backtrace_symbols_fd( void **buffer, int size, int fd )
324 {
325     FILE    *fp = fdopen( fd, "w" );
326 
327     if ( fp )
328     {
329         void **pFramePtr;
330 
331         for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- )
332         {
333             Dl_info     dli;
334             ptrdiff_t   offset;
335 
336             if ( 0 != dladdr( *pFramePtr, &dli ) )
337             {
338                 if ( dli.dli_fname && dli.dli_fbase )
339                 {
340                     offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase;
341                     fprintf( fp, "%s+0x%" SAL_PRI_PTRDIFFT "x", dli.dli_fname, offset );
342                 }
343                 if ( dli.dli_sname && dli.dli_saddr )
344                 {
345                     offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr;
346                     fprintf( fp, "(%s+0x%" SAL_PRI_PTRDIFFT "x)", dli.dli_sname, offset );
347                 }
348             }
349             fprintf( fp, "[%p]\n", *pFramePtr );
350         }
351 
352         fflush( fp );
353         fclose( fp );
354     }
355 }
356 
357 #endif /* defined MACOSX */
358