xref: /trunk/main/sal/osl/unx/backtrace.c (revision 9664d1e0)
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 
backtrace(void ** buffer,int max_frames)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 
backtrace_symbols_fd(void ** buffer,int size,int fd)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 
backtrace(void ** buffer,int max_frames)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 
backtrace_symbols_fd(void ** buffer,int size,int fd)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 
backtrace(void ** buffer,int max_frames)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 
backtrace_symbols_fd(void ** buffer,int size,int fd)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 
backtrace(void ** buffer,int max_frames)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 
backtrace_symbols_fd(void ** buffer,int size,int fd)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