blob: 62f892dd73a139aacd568cc4a6a2bf3ead7d1523 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#ifdef SOLARIS
#include <dlfcn.h>
#include <pthread.h>
#include <setjmp.h>
#include <stdio.h>
#include <sys/frame.h>
#include "backtrace.h"
#if defined(SPARC)
#if defined IS_LP64
#define FRAME_PTR_OFFSET 1
#define FRAME_OFFSET 0
#define STACK_BIAS 0x7ff
#else
#define FRAME_PTR_OFFSET 1
#define FRAME_OFFSET 0
#define STACK_BIAS 0
#endif
#elif defined( INTEL )
#define FRAME_PTR_OFFSET 3
#define FRAME_OFFSET 0
#define STACK_BIAS 0
#else
#error Unknown Solaris target platform.
#endif /* defined SPARC or INTEL */
int backtrace( void **buffer, int max_frames )
{
jmp_buf ctx;
long fpval;
struct frame *fp;
int i;
/* flush register windows */
#ifdef SPARC
asm("ta 3");
#endif
/* get stack- and framepointer */
setjmp(ctx);
fpval = ((long*)(ctx))[FRAME_PTR_OFFSET];
fp = (struct frame*)((char*)(fpval) + STACK_BIAS);
for (i = 0; (i < FRAME_OFFSET) && (fp != 0); i++)
fp = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS);
/* iterate through backtrace */
for (i = 0; (fp != 0) && (fp->fr_savpc != 0) && (i < max_frames); i++)
{
/* saved (prev) frame */
struct frame * prev = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS);
/* store frame */
*(buffer++) = (void*)(fp->fr_savpc);
/* prev frame (w/ stack growing top down) */
fp = (prev > fp) ? prev : 0;
}
/* return number of frames stored */
return i;
}
void backtrace_symbols_fd( void **buffer, int size, int fd )
{
FILE *fp = fdopen( fd, "w" );
if ( fp )
{
void **pFramePtr;
for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- )
{
Dl_info dli;
ptrdiff_t offset;
if ( 0 != dladdr( *pFramePtr, &dli ) )
{
if ( dli.dli_fname && dli.dli_fbase )
{
offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase;
fprintf( fp, "%s+0x%x", dli.dli_fname, offset );
}
if ( dli.dli_sname && dli.dli_saddr )
{
offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr;
fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset );
}
}
fprintf( fp, "[0x%x]\n", *pFramePtr );
}
fflush( fp );
fclose( fp );
}
}
#endif /* defined SOLARIS */
#if defined FREEBSD || defined NETBSD
#include <dlfcn.h>
#include <pthread.h>
#include <setjmp.h>
#include <stddef.h>
#include <stdio.h>
#include "backtrace.h"
#define FRAME_PTR_OFFSET 1
#define FRAME_OFFSET 0
int backtrace( void **buffer, int max_frames )
{
struct frame *fp;
jmp_buf ctx;
int i;
/* get stack- and framepointer */
setjmp(ctx);
fp = (struct frame*)(((size_t*)(ctx))[FRAME_PTR_OFFSET]);
for ( i=0; (i<FRAME_OFFSET) && (fp!=0); i++)
fp = fp->fr_savfp;
/* iterate through backtrace */
for (i=0; fp && fp->fr_savpc && i<max_frames; i++)
{
/* store frame */
*(buffer++) = (void *)fp->fr_savpc;
/* next frame */
fp=fp->fr_savfp;
}
return i;
}
void backtrace_symbols_fd( void **buffer, int size, int fd )
{
FILE *fp = fdopen( fd, "w" );
if ( fp )
{
void **pFramePtr;
for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- )
{
Dl_info dli;
ptrdiff_t offset;
if ( 0 != dladdr( *pFramePtr, &dli ) )
{
if ( dli.dli_fname && dli.dli_fbase )
{
offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase;
fprintf( fp, "%s+0x%x", dli.dli_fname, offset );
}
if ( dli.dli_sname && dli.dli_saddr )
{
offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr;
fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset );
}
}
fprintf( fp, "[0x%x]\n", *pFramePtr );
}
fflush( fp );
fclose( fp );
}
}
#endif /* defined FREEBSD */
#ifdef LINUX
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <dlfcn.h>
#include <pthread.h>
#include <setjmp.h>
#include <stdio.h>
#include "backtrace.h"
#if defined(SPARC)
#define FRAME_PTR_OFFSET 1
#define FRAME_OFFSET 0
#else
#error Unknown Linux target platform.
#endif /* defined SPARC or INTEL */
typedef int ptrdiff_t;
int backtrace( void **buffer, int max_frames )
{
struct frame *fp;
jmp_buf ctx;
int i;
/* flush register windows */
#ifdef SPARC
asm("ta 3");
#endif
/* get stack- and framepointer */
setjmp(ctx);
fp = (struct frame*)(((size_t*)(ctx))[FRAME_PTR_OFFSET]);
for ( i=0; (i<FRAME_OFFSET) && (fp!=0); i++)
fp = fp->fr_savfp;
/* iterate through backtrace */
for (i=0; fp && fp->fr_savpc && i<max_frames; i++)
{
/* store frame */
*(buffer++) = (void *)fp->fr_savpc;
/* next frame */
fp=fp->fr_savfp;
}
return i;
}
void backtrace_symbols_fd( void **buffer, int size, int fd )
{
FILE *fp = fdopen( fd, "w" );
if ( fp )
{
void **pFramePtr;
for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- )
{
Dl_info dli;
ptrdiff_t offset;
if ( 0 != dladdr( *pFramePtr, &dli ) )
{
if ( dli.dli_fname && dli.dli_fbase )
{
offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase;
fprintf( fp, "%s+0x%x", dli.dli_fname, offset );
}
if ( dli.dli_sname && dli.dli_saddr )
{
offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr;
fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset );
}
}
fprintf( fp, "[0x%x]\n", *pFramePtr );
}
fflush( fp );
fclose( fp );
}
}
#endif /* defined LINUX */
#if defined( MACOSX )
#include <dlfcn.h>
#include <stdio.h>
#include "backtrace.h"
typedef unsigned ptrdiff_t;
/* glib backtrace is only available on MacOsX 10.5 or higher
so we do it on our own */
int backtrace( void **buffer, int max_frames )
{
void **frame = (void **)__builtin_frame_address(0);
void **bp = ( void **)(*frame);
void *ip = frame[1];
int i;
for ( i = 0; bp && ip && i < max_frames; i++ )
{
*(buffer++) = ip;
ip = bp[1];
bp = (void**)(bp[0]);
}
return i;
}
void backtrace_symbols_fd( void **buffer, int size, int fd )
{
FILE *fp = fdopen( fd, "w" );
if ( fp )
{
void **pFramePtr;
for ( pFramePtr = buffer; size > 0 && pFramePtr && *pFramePtr; pFramePtr++, size-- )
{
Dl_info dli;
ptrdiff_t offset;
if ( 0 != dladdr( *pFramePtr, &dli ) )
{
if ( dli.dli_fname && dli.dli_fbase )
{
offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_fbase;
fprintf( fp, "%s+0x%x", dli.dli_fname, offset );
}
if ( dli.dli_sname && dli.dli_saddr )
{
offset = (ptrdiff_t)*pFramePtr - (ptrdiff_t)dli.dli_saddr;
fprintf( fp, "(%s+0x%x)", dli.dli_sname, offset );
}
}
fprintf( fp, "[0x%x]\n", (unsigned int)*pFramePtr );
}
fflush( fp );
fclose( fp );
}
}
#endif /* defined MACOSX */