/*
 * Copyright (C) 2000 Sasha Vasko <sasha at aftercode.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __CYGWIN__
# define XWRAP_H_HEADER_INCLUDED
# undef BOOL
# undef INT32
# include <w32api/windows.h>
# include <w32api/imagehlp.h>
#endif


#include "astypes.h"
#include "output.h"
#include "selfdiag.h"


#ifdef HAVE_EXECINFO_H
# include <execinfo.h>
# ifdef HAVE_BACKTRACE_SYMBOLS
#  define GLIBC_BACKTRACE_FUNC 	backtrace_symbols
# else
#  define GLIBC_BACKTRACE_FUNC 	__backtrace_symbols
# endif
#endif


#ifdef HAVE_LINK_H
# include <link.h>
#endif

#ifdef HAVE_ELF_H
# include <elf.h>
#endif

#include <signal.h>

#ifdef HAVE_SIGCONTEXT
# include <asm/sigcontext.h>
#else
struct sigcontext;							   /* just in case for easier portability */
#endif



typedef struct proc_tables
{

#ifdef HAVE_LINK_H
	struct r_debug *debug;
#endif

#ifdef HAVE_ELF_H
	Elf32_Sym    *symbols;
	Elf32_Word   *sym_hash;
#endif
	int           sym_ent_size;
	int           sym_ent_num;

	char         *strings;
	int           str_tabl_size;

	void         *pltgot;

}
proc_tables;

proc_tables   _ptabs;
char         *_elf_start = (char *)0x08048000;


void
get_proc_tables (proc_tables * ptabs)
{
#ifdef HAVE_ELF_H
# if (defined(HAVE_ELF32_DYN_D_TAG) || defined(HAVE_ELF64_DYN_D_TAG)) && HAVE_DECL_ELFW
	ElfW (Dyn) * dyn;

	memset (ptabs, 0x00, sizeof (proc_tables));
	for (dyn = _DYNAMIC; dyn != NULL && dyn->d_tag != DT_NULL; ++dyn)
		switch (dyn->d_tag)
		{
			 /* symbols */
		 case DT_SYMTAB:
			 ptabs->symbols = (Elf32_Sym *) dyn->d_un.d_ptr;
			 break;
		 case DT_HASH:
			 ptabs->sym_hash = (Elf32_Word *) dyn->d_un.d_ptr;
			 break;
		 case DT_SYMENT:
			 ptabs->sym_ent_size = dyn->d_un.d_val;
			 break;
			 /* strings */
		 case DT_STRTAB:
			 ptabs->strings = (char *)dyn->d_un.d_ptr;
			 break;
		 case DT_STRSZ:
			 ptabs->str_tabl_size = dyn->d_un.d_val;
			 break;
			 /* debug info */
		 case DT_DEBUG:
#  ifdef HAVE_LINK_H
			 ptabs->debug = (struct r_debug *)dyn->d_un.d_ptr;
#  endif			 
			 break;
			 /* GOT/PLT */
		 case DT_PLTGOT:
			 ptabs->pltgot = (void *)dyn->d_un.d_ptr;
			 break;
		}
	if (ptabs->sym_hash != NULL)
		ptabs->sym_ent_num = *(ptabs->sym_hash + 1);
# endif
#endif /* HAVE_ELF_H */
}

#if defined(HAVE_SIGCONTEXT)
static void
print_elf_data (proc_tables * ptabs)
{
	fprintf (stderr, "found data structures :\n");
	fprintf (stderr, "   Symbols at 0x%8.8X (%d)\n", ptabs->symbols);
	fprintf (stderr, "   Symbol's hash at 0x%8.8X\n", ptabs->sym_hash);
	fprintf (stderr, "   Symbol entry size = %d, entries = %d\n", ptabs->sym_ent_size, ptabs->sym_ent_num);
	fprintf (stderr, "   Strings at 0x%8.8X (%d), size: %d\n", ptabs->strings, ptabs->str_tabl_size);
	fprintf (stderr, "   Debug at 0x%8.8X (%d)\n", ptabs->debug);
	fprintf (stderr, "   PltGOT at 0x%8.8X (%d)\n", ptabs->pltgot);

	if (ptabs->strings != NULL && ptabs->str_tabl_size > 2)
	{
		int           i, last_str = 0;

		fprintf (stderr, "strings table :\n");
		for (i = 0; i < ptabs->str_tabl_size - 1; i++)
			if (ptabs->strings[i] == '\0')
			{
				fprintf (stderr, "   %d, %d :[%s]\n", last_str, i, &(ptabs->strings[last_str]));
				last_str = i + 1;
			}
		fprintf (stderr, "   %d, %d : [%s]\n", last_str, i, &(ptabs->strings[last_str]));
	}
	if (ptabs->debug != NULL)
	{
		struct link_map *plm = ptabs->debug->r_map;

		fprintf (stderr, "debug info :\n");
		for (; plm != NULL; plm = plm->l_next)
		{
			fprintf (stderr, "   [0x%8.8X]:[%s]\n", plm->l_addr, plm->l_name);
		}
	}
# ifdef HAVE_ELF32_ADDR	 
	if (ptabs->symbols != NULL && ptabs->sym_ent_size == sizeof (Elf32_Sym))
	{
		int           i;
		Elf32_Sym    *ptr = ptabs->symbols + 1;

		fprintf (stderr, "symbols info : (elem size = %d bytes)\n", ptabs->sym_ent_size);

		for (i = 1; i < ptabs->sym_ent_num; i++)
		{
			fprintf (stderr, "   [0x%8.8X][%d][%X][%d][%s]\n", ptr->st_value,
					 ptr->st_size, ptr->st_info, ptr->st_shndx, ptabs->strings + (ptr->st_name));
			ptr++;
		}
	}
# endif
# ifdef HAVE_ELF64_ADDR	 
	if (ptabs->symbols != NULL && ptabs->sym_ent_size == sizeof (Elf64_Sym))
	{
		int           i;
		Elf64_Sym    *ptr = (Elf64_Sym *) (ptabs->symbols + 1);

		fprintf (stderr, "symbols info : (elem size = %d bytes)\n", ptabs->sym_ent_size);
		for (i = 1; i < ptabs->sym_ent_num; i++)
		{
			fprintf (stderr, "   [0x%8.8X][%d][%X][%d][%s]\n", ptr->st_value,
					 ptr->st_size, ptr->st_info, ptr->st_shndx, ptabs->strings + (ptr->st_name));
			ptr++;
		}
	}
# endif
}
#endif


static char  *unknown = "unknown";

const char*
find_func_symbol (void *addr, long *offset)
{
#ifdef HAVE_ELF_H
	long          min_offset = 0x0fffffff, curr_offset;
	char         *selected = unknown;

	*offset = -1;
	if (_ptabs.symbols == NULL || _ptabs.strings == NULL)
		return unknown;

# if defined(HAVE_ELF64_ADDR)
	if (_ptabs.sym_ent_size == sizeof (Elf64_Sym))
	{
		int           i;
		Elf64_Sym    *ptr = (Elf64_Sym *) (_ptabs.symbols + 1);
		Elf64_Addr    addr64 = (Elf64_Addr)addr;

		for (i = 1; i < _ptabs.sym_ent_num; i++)
		{
			if (ptr->st_value <= addr64 && ELF64_ST_TYPE (ptr->st_info) == STT_FUNC)
			{
				curr_offset = addr64 - ptr->st_value;
				if (curr_offset < min_offset && curr_offset < ptr->st_size)
				{
					selected = _ptabs.strings + (ptr->st_name);
					min_offset = curr_offset;
				}
			}
			ptr++;
		}
	}
# elif defined(HAVE_ELF32_ADDR)
	if (_ptabs.sym_ent_size == sizeof (Elf32_Sym))
	{
		int           i; 
		Elf32_Sym    *ptr = _ptabs.symbols + 1;
		Elf32_Addr    addr32 = (Elf32_Addr)addr;

		for (i = 1; i < _ptabs.sym_ent_num; i++)
		{
			if (ptr->st_value <= addr32 && ELF32_ST_TYPE (ptr->st_info) == STT_FUNC)
			{
				curr_offset = addr32 - ptr->st_value;
				if (curr_offset < min_offset && curr_offset < ptr->st_size)
				{
					selected = _ptabs.strings + (ptr->st_name);
					min_offset = curr_offset;
				}
			}
			ptr++;
		}
	}
# endif
	*offset = min_offset;
	return selected;
#elif defined(__CYGWIN__)

	{
		
		*offset = 0 ;
# if 0
		{		
			static int imhelp_symbols_inited = FALSE ; 
#  define MAX_IMAGEHLP_SYM_NAME_LEN	128
    	    static BYTE symbolBuffer[ sizeof(IMAGEHLP_SYMBOL) + MAX_IMAGEHLP_SYM_NAME_LEN + 1 ];
        	static PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL)symbolBuffer;
        	DWORD symDisplacement = 0;  // Displacement of the input address,
		
			pSymbol->SizeOfStruct = sizeof(symbolBuffer);
        	pSymbol->MaxNameLength = MAX_IMAGEHLP_SYM_NAME_LEN;
			
			if( !imhelp_symbols_inited ) 
			{
				if ( !SymInitialize( GetCurrentProcess(), 0, TRUE ) )	
					return unknown;
				imhelp_symbols_inited = TRUE ;
			}	 
        
			if ( SymGetSymFromAddr(GetCurrentProcess(), (DWORD)addr,
                                	&symDisplacement, pSymbol) )
        	{
				*offset = symDisplacement ; 
				return pSymbol->Name ;
        	}
		}
# endif
		return unknown;
	}		  
#else
	*offset = 0;
    return unknown;
#endif /* HAVE_ELF_H */
}

#if defined(HAVE_SIGCONTEXT)
static void
print_lib_list ()
{
#if defined(HAVE_LINK_H)
	if (_ptabs.debug != NULL)
	{
		struct link_map *plm = _ptabs.debug->r_map;

		fprintf (stderr, " Loaded dynamic libraries :\n");
		for (; plm != NULL; plm = plm->l_next)
		{
			if (plm->l_addr != 0x00 && plm->l_name != NULL)
				fprintf (stderr, "   [0x%8.8lx]:[%s]\n", (unsigned long)plm->l_addr, plm->l_name);
		}
	}
#endif
}

static void
print_signal_context (struct sigcontext *psc)
{
	if (psc)
	{
		register int  i;

		fprintf (stderr, " Signal Context :\n");
		fprintf (stderr, "  Registers\n");
		i = 0;								   /* to avoid warnings */
# if defined(_ASMi386_SIGCONTEXT_H)
		fprintf (stderr, "  EAX: 0x%8.8lX", (unsigned long)(psc->eax));
		fprintf (stderr, "  EBX: 0x%8.8lX", (unsigned long)(psc->ebx));
		fprintf (stderr, "  ECX: 0x%8.8lX", (unsigned long)(psc->ecx));
		fprintf (stderr, "  EDX: 0x%8.8lX\n", (unsigned long)(psc->edx));
		fprintf (stderr, "  ESP: 0x%8.8lX", (unsigned long)(psc->esp));
		fprintf (stderr, "  EBP: 0x%8.8lX", (unsigned long)(psc->ebp));
		fprintf (stderr, "  EIP: 0x%8.8lX\n", (unsigned long)(psc->eip));
		fprintf (stderr, "  ESI: 0x%8.8lX", (unsigned long)(psc->esi));
		fprintf (stderr, "  EDI: 0x%8.8lX\n", (unsigned long)(psc->edi));
# elif defined(_ASMAXP_SIGCONTEXT_H) || defined(__ASM_MIPS_SIGCONTEXT_H) || defined(__ASM_SH_SIGCONTEXT_H)
		for (; i < 32; i++)
			fprintf (stderr, "  #%d: 0x%8.8lX\n", i, (unsigned long)(psc->sc_regs[i]));
# elif defined(_ASM_PPC_SIGCONTEXT_H)
		for (; i < 32; i++)
			fprintf (stderr, "  #%d: 0x%8.8lX\n", i, (unsigned long)(psc->regs->gpr[i]));
# endif
	}
}
#endif
#if defined(_ASMi386_SIGCONTEXT_H)
#define HAVE_PRINT_MY_BACKTRACE
static void
print_my_backtrace (long *ebp, long *esp, long *eip)
{
	int           frame_no = 0;

	fprintf (stderr, " Stack Backtrace :\n");

# if defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_BACKTRACE)
	{
#  define BACKTRACE_ARRAY_SIZE 64
		void *array[BACKTRACE_ARRAY_SIZE];
		size_t size;
		size = backtrace (array, BACKTRACE_ARRAY_SIZE);
		backtrace_symbols_fd (array, size, fileno(stderr)); /* most reliable way !!! */
		return;
#  undef BACKTRACE_ARRAY_SIZE		
	}
# endif		

	if (ebp < (long *)0x08074000			   /* stack can't possibly go below that */
		)
	{
		long          offset = 0;
		const char   *func_name = NULL;

		fprintf (stderr, "  heh, looks like we've got corrupted stack, so no backtrace for you.\n");
		if (eip != NULL)
		{
			fprintf (stderr, "  all I can say is that we failed at 0x%lX", (unsigned long)eip);
			func_name = find_func_symbol ((void *)eip, &offset);
			if (func_name != unknown)
				fprintf (stderr, " in [%s+0x%lX(%lu)]", func_name, offset, offset);
# if !defined(__CYGWIN__)
			else
			{
				void *peip = &eip;
			    char **dummy = GLIBC_BACKTRACE_FUNC (peip, 1);
				if( dummy ) 
				{
	                func_name = *dummy ;
					if (*func_name != '[')
						fprintf (stderr, " in %s()", func_name);
#  ifdef HAVE_BACKTRACE_SYMBOLS			
					free( dummy );
#  endif /* HAVE_BACKTRACE_SYMBOLS */

				}
			}
# endif
			fprintf (stderr, "\n");
		}
		return;
	}

	fprintf (stderr, "   FRAME       NEXT FRAME  FUNCTION\n");
	while (ebp != NULL && ebp > (long *)0x08074000	/* stack can't possibly go below that */
		)
	{
		long          offset = 0;
		const char   *func_name = NULL;

		frame_no++;
		fprintf (stderr, "  0x%8.8lX", (unsigned long)ebp);
		fprintf (stderr, "  0x%8.8lX", (unsigned long)*(ebp));
		fprintf (stderr, "  0x%8.8lX", (unsigned long)esp);
		if (*(ebp) == 0)
			fprintf (stderr, "[program entry point]\n");
		else
		{
			func_name = find_func_symbol ((void *)esp, &offset);
            if (func_name == unknown && frame_no == 1 && eip != NULL )  /* good fallback for current frame */
				func_name = find_func_symbol ((void *)eip, &offset);

			if (func_name == unknown)
			{
# ifdef HAVE_EXECINFO_H
				void *pesp = &esp;
                char **dummy = GLIBC_BACKTRACE_FUNC (pesp, 1);
				if( dummy ) 
				{
                	func_name = *dummy;
					if (*func_name != '[')
						fprintf (stderr, "  [%s]", func_name);
					else
						fprintf (stderr, "  [some silly code]");
#  ifdef HAVE_BACKTRACE_SYMBOLS			
					free( dummy );
#  endif /* HAVE_BACKTRACE_SYMBOLS */
				}else
# endif
					fprintf (stderr, "  [some silly code]");
			} else
				fprintf (stderr, "  [%s+0x%lX(%lu)]", func_name, offset, offset);
			fprintf (stderr, "\n");
		}
		esp = (long *)*(ebp + 1);
		ebp = (long *)*(ebp);
	}
}
#endif

#define MAX_CALL_DEPTH 32                      /* if you change it here  - then change below as well!!! */

#if !defined(HAVE_BACKTRACE) || !defined(HAVE_BACKTRACE_SYMBOLS)

static long**
get_call_list()
{
    static long * call_list[MAX_CALL_DEPTH+1] = {NULL};
# if (defined(__GNUC__)&& defined(_ASMi386_SIGCONTEXT_H)) || defined(__CYGWIN__)
    if( __builtin_frame_address(0) == NULL ) goto done ;
    if( __builtin_frame_address(1) == NULL ) goto done ;

    if( __builtin_frame_address(2) == NULL ) goto done ;
    if( (call_list[0]= __builtin_return_address(2)) == NULL ) goto done ;

    if( __builtin_frame_address(3) == NULL ) goto done ;
    if( (call_list[1] = __builtin_return_address(3)) == NULL ) goto done ;

    if( __builtin_frame_address(4) == NULL ) goto done ;
    if( (call_list[2] = __builtin_return_address(4)) == NULL ) goto done ;

    if( __builtin_frame_address(5) == NULL ) goto done ;
    if( (call_list[3] = __builtin_return_address(5)) == NULL ) goto done ;

    if( __builtin_frame_address(6) == NULL ) goto done ;
    if( (call_list[4] = __builtin_return_address(6)) == NULL ) goto done ;

    if( __builtin_frame_address(7) == NULL ) goto done ;
    if( (call_list[5] = __builtin_return_address(7)) == NULL ) goto done ;

    if( __builtin_frame_address(8) == NULL ) goto done ;
    if( (call_list[6] = __builtin_return_address(8)) == NULL ) goto done ;

    if( __builtin_frame_address(9) == NULL ) goto done ;
    if( (call_list[7] = __builtin_return_address(9)) == NULL ) goto done ;

    if( __builtin_frame_address(10) == NULL ) goto done ;
    if( (call_list[8] = __builtin_return_address(10)) == NULL ) goto done ;

    if( __builtin_frame_address(11) == NULL ) goto done ;
    if( (call_list[9] = __builtin_return_address(11)) == NULL ) goto done ;

    if( __builtin_frame_address(12) == NULL ) goto done ;
    if( (call_list[10] = __builtin_return_address(12)) == NULL ) goto done ;

    if( __builtin_frame_address(13) == NULL ) goto done ;
    if( (call_list[11] = __builtin_return_address(13)) == NULL ) goto done ;

    if( __builtin_frame_address(14) == NULL ) goto done ;
    if( (call_list[12] = __builtin_return_address(14)) == NULL ) goto done ;

    if( __builtin_frame_address(15) == NULL ) goto done ;
    if( (call_list[13] = __builtin_return_address(15)) == NULL ) goto done ;

    if( __builtin_frame_address(16) == NULL ) goto done ;
    if( (call_list[14] = __builtin_return_address(16)) == NULL ) goto done ;

    if( __builtin_frame_address(17) == NULL ) goto done ;
    if( (call_list[15] = __builtin_return_address(17)) == NULL ) goto done ;

    if( __builtin_frame_address(18) == NULL ) goto done ;
    if( (call_list[16] = __builtin_return_address(18)) == NULL ) goto done ;

    if( __builtin_frame_address(19) == NULL ) goto done ;
    if( (call_list[17] = __builtin_return_address(19)) == NULL ) goto done ;

    if( __builtin_frame_address(20) == NULL ) goto done ;
    if( (call_list[18] = __builtin_return_address(20)) == NULL ) goto done ;

    if( __builtin_frame_address(21) == NULL ) goto done ;
    if( (call_list[19] = __builtin_return_address(21)) == NULL ) goto done ;

    if( __builtin_frame_address(22) == NULL ) goto done ;
    if( (call_list[20] = __builtin_return_address(22)) == NULL ) goto done ;

    if( __builtin_frame_address(23) == NULL ) goto done ;
    if( (call_list[21] = __builtin_return_address(23)) == NULL ) goto done ;

    if( __builtin_frame_address(24) == NULL ) goto done ;
    if( (call_list[22] = __builtin_return_address(24)) == NULL ) goto done ;

    if( __builtin_frame_address(25) == NULL ) goto done ;
    if( (call_list[23] = __builtin_return_address(25)) == NULL ) goto done ;

    if( __builtin_frame_address(26) == NULL ) goto done ;
    if( (call_list[24] = __builtin_return_address(26)) == NULL ) goto done ;

    if( __builtin_frame_address(27) == NULL ) goto done ;
    if( (call_list[25] = __builtin_return_address(27)) == NULL ) goto done ;

    if( __builtin_frame_address(28) == NULL ) goto done ;
    if( (call_list[26] = __builtin_return_address(28)) == NULL ) goto done ;

    if( __builtin_frame_address(29) == NULL ) goto done ;
    if( (call_list[27] = __builtin_return_address(29)) == NULL ) goto done ;

    if( __builtin_frame_address(30) == NULL ) goto done ;
    if( (call_list[28] = __builtin_return_address(30)) == NULL ) goto done ;

    if( __builtin_frame_address(31) == NULL ) goto done ;
    if( (call_list[29] = __builtin_return_address(31)) == NULL ) goto done ;

    if( __builtin_frame_address(32) == NULL ) goto done ;
    if( (call_list[30] = __builtin_return_address(32)) == NULL ) goto done ;

    call_list[31] = NULL;
done:
# endif
    return call_list;
}
#endif /* !defined(HAVE_BACKTRACE) || !defined(HAVE_BACKTRACE_SYMBOLS) */

#if defined(HAVE_SIGCONTEXT)
static void
print_diag_info (struct sigcontext *psc)
{
	get_proc_tables (&_ptabs);
	print_elf_data (&_ptabs);				   /* only while debugging this stuff */
	fprintf (stderr, "Printing Debug Information :\n");
	print_lib_list ();
	if (psc)
	{
		print_signal_context (psc);
#if defined(HAVE_PRINT_MY_BACKTRACE)
		print_my_backtrace ((long *)(psc->ebp), (long *)(psc->esp), (long *)(psc->eip));
#endif
	}
}
#endif

static void
sigsegv_handler (int signum
#if defined(HAVE_SIGCONTEXT)
				 , struct sigcontext sc
#endif
	)
{
	static int    level = 0;
	const char  *MyName = get_application_name();

	if (signum == SIGSEGV)
	{
		fprintf (stderr, "Segmentation Fault trapped");
		if (level > 0)
			exit (1);						   /* sigsegv in sigsegv */
		level++;
		fprintf (stderr, " in %s.\n", MyName);
	} else
		fprintf (stderr, "Non-critical Signal %d trapped in %s.\n", signum, MyName);

#if defined(HAVE_SIGCONTEXT)
	print_diag_info (&sc);
#else
    print_simple_backtrace ();
#endif
	if (signum == SIGSEGV)
	{
		fprintf (stderr,
				 "Please collect all the listed information and open an issue at\n\thttps://github.com/afterstep/afterstep/issues.\n");
		fprintf (stderr,
				 "If a core dump was generated by this fault, please examine it with gdb and attach results to your report.\n");
		fprintf (stderr, " You can use the following sequence to do so :\n");
		fprintf (stderr, "   gdb -core core /usr/bin/afterstep\n");
		fprintf (stderr, "   gdb>backtrace\n");
		fprintf (stderr, "   gdb>info frame\n");
		fprintf (stderr, "   gdb>info all-registers\n");
		fprintf (stderr, "   gdb>disassemble\n");
		exit (1);
	}
}

/********************************************************************/ 
/********************************************************************/ 
/********************************************************************/ 
/*   Public Interfaces : */
void
set_signal_handler (int sig_num)
{
	signal (sig_num, (void *)sigsegv_handler);
}

static char _as_func_name_return[256];

const char *
get_caller_func ()
{
  const char *func_name = unknown;
	void       *to_free = NULL; 
#if defined(__GNUC__) || defined(__CYGWIN__)

# if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
	{
#  define BACKTRACE_ARRAY_SIZE 3		/* we only need previous function: 0 - us, 1 - calliee, 2 - caller */
		void *array[BACKTRACE_ARRAY_SIZE];
		size_t size;
		char **strings;
		memset( array, 0x00, sizeof(array) );
		size = backtrace (array, BACKTRACE_ARRAY_SIZE);
		strings = backtrace_symbols (array, size);
		func_name = strings[size > 1? (size>2?2:1):0]; /* we need two levels up ? */
		to_free = strings;
	}
#  undef BACKTRACE_ARRAY_SIZE	

# else /* defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) */
	{
    	int           call_no = 0;
    	long         **ret_addr ;

    	ret_addr = get_call_list();
    	if(ret_addr[0] != NULL )
    	{
			long          offset = 0;

        	get_proc_tables (&_ptabs);
        	func_name = find_func_symbol ((void *)ret_addr[call_no], &offset);
#  ifdef HAVE_EXECINFO_H
        	if (func_name == unknown)
        	{
            	char **dummy = GLIBC_BACKTRACE_FUNC ((void **)&(ret_addr[call_no]), 1);
#   ifdef HAVE_BACKTRACE_SYMBOLS			
				to_free = dummy ;
#   endif /* HAVE_BACKTRACE_SYMBOLS */
            	func_name = *dummy ;
        	}
#  endif /* HAVE_EXECINFO_H */
    	}
  }
# endif /* defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) */
#endif  /* defined(__GNUC__) || defined(__CYGWIN__) */

	if( func_name == NULL )
		func_name = unknown ;
	strncpy( _as_func_name_return, func_name, 255 );
	_as_func_name_return[255] = '\0' ;
	if( to_free != NULL  ) 
		free(to_free);
	
    return &(_as_func_name_return[0]);
}


void
print_simple_backtrace ()
{
#if defined(__GNUC__)
    int           call_no = 0;

    fprintf (stderr, " Call Backtrace :\n");
    fprintf (stderr, " CALL#: ADDRESS:    FUNCTION:\n");

# if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
	{
#   define BACKTRACE_ARRAY_SIZE 64		/* we only need previous function ! */
		void *array[BACKTRACE_ARRAY_SIZE];
		size_t size;
		char **strings;
		memset( array, 0x00, sizeof(array));
		size = backtrace (array, BACKTRACE_ARRAY_SIZE);
		strings = backtrace_symbols (array, size);
		if( strings != NULL ) 
		{
			/* call_no == 0 - is ourselves - skipping it */
			for( call_no = 1 ; call_no < size ; ++call_no )
				if( strings[call_no][0] != '[' ) 
	        		fprintf (stderr, " %5u  %p  [%s]\n", call_no, array[call_no], strings[call_no] );
				else 		
					fprintf (stderr, " %5u  %p  %s\n", call_no, array[call_no], strings[call_no] );
			free(strings);
		}else
		{
#   ifdef HAVE_BACKTRACE_SYMBOLS_FD
			backtrace_symbols_fd(array, size, fileno(stderr));
#   endif		
		}
	}
#  undef BACKTRACE_ARRAY_SIZE	
# else /* defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) */
	{
	    long         **ret_addr = get_call_list();
    	if( ret_addr[0] == NULL )
        	return ;
		get_proc_tables (&_ptabs);
    	while (ret_addr[call_no] != NULL )
    	{
			long          offset = 0;
			const char   *func_name = NULL;

        	fprintf (stderr, " %5u  0x%8.8lX", call_no, (unsigned long)(ret_addr[call_no]) );

        	func_name = find_func_symbol ((void *)ret_addr[call_no], &offset);
        	if (func_name == unknown)
        	{
#  ifdef HAVE_EXECINFO_H
		    	char **dummy = GLIBC_BACKTRACE_FUNC ((void **)&(ret_addr[call_no]), 1);
				if( dummy ) 
				{
	            	func_name = *dummy;
    	        	if (*func_name != '[')
        	        	fprintf (stderr, "  [%s]", func_name);
            		else
                		fprintf (stderr, "  [some silly code]");
#   ifdef HAVE_BACKTRACE_SYMBOLS			
					free( dummy );
#   endif /* HAVE_BACKTRACE_SYMBOLS */
				}else
#  endif
					fprintf (stderr, "  [some silly code]");				
        	} else
            	fprintf (stderr, "  [%s+0x%lX(%lu)]", func_name, offset, offset);
        	fprintf (stderr, "\n");
        	call_no++;
    	}
	}
# endif /* defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) */
#endif /* defined(__GNUC__) */
}

