/* ***********************IMPORTANT *********************************************
 *  Copyright (C) 2004-2007 Thierry Lagarde <tlagarde@users.sourceforge.net>
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License.
 *
 *
 *                      ********************
 *
 *
 *  This program 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 Library General Public License for more details.
 *
 *
 *                      ********************
 *
 *
 * You are highly encouraged to send your changes to <tlagarde@users.sourceforge.net>
 * for possible incorporation into the main distribution.
 * By sending these changes to <tlagarde@users.sourceforge.net>,
 * it is assumed that you are offering <tlagarde@users.sourceforge.net>
 * the unlimited, non-exclusive right to reuse, modify, and relicense the code.
 *
 *
 *                      ********************
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **************************************************************************************/
#ifdef __BACKTRACE_ENABLE

#include <execinfo.h>
#include <malloc.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "BackTrace.h"
#include "Macro.h"
#include "Tools.h"

void init_backtrace(){
	addr2line = Cherche_Chemin_Executable("addr2line");
}


void display_backtrace (struct struct_Cle_Privee *pCle,void *backtraceList[],gint Nb_Ligne)
{
	PROTECT_CODE(Semaphore_BackTrace);
	
	void     *bt[MAX_BACKTRACE_SIZE];
	FILE     *pipe_cmd = NULL;
	int       used,Taille_Info_Memoire;
	
	if (backtraceList==NULL){
	    used = backtrace ((void **) bt, MAX_BACKTRACE_SIZE);
		if (pCle==NULL)
			printf("backtrace() returned %d addresses\n", used);
		else
			Log_free (pCle,g_strdup_printf("backtrace() returned %d addresses\n", used));
	}
	else {
		int i;
		
		for (i=0;i<Nb_Ligne;i++)
			bt[i] = backtraceList[i];
		used = Nb_Ligne;
	}
	
	char    **bt_strings = NULL;
	char    **the_backtrace = backtrace_symbols (bt, used);
	char     *cmd = malloc (sizeof (char) * (strlen (addr2line) + strlen (binary_name) + 20 * used));
	char     *curr = cmd;
	char    **addrs = malloc (sizeof (char *) * used);
	char      buff[256], line_func[1024], line_pos[1024];
	int       addr_len = 0;
	int       i;
	
	if (pCle==NULL)
		printf("---------- BACKTRACE ----------\n");
	else
		Log (pCle, "---------- BACKTRACE ----------\n");
	
	if (the_backtrace == NULL) {
		if (pCle==NULL)
			printf("backtrace_symbols : %s\n", strerror (errno));
		else
			Log_free (pCle,g_strdup_printf("backtrace_symbols : %s\n", strerror (errno)));
         return;
     }
	
	if (!used){	
		DEPROTECT_CODE(Semaphore_BackTrace);
		return;
	}
	curr += sprintf (curr, "%s -f -s -e  %s ", addr2line, binary_name);
	for (i = 0; i < used; i++) {
		char     *p;

		snprintf (buff, 256, "%s", strchr (the_backtrace[i], '[') + 1);
		p = strchr (buff, ']');
		*p = '\0';
		addrs[i] = strdup (buff);
		curr += sprintf (curr, "%s ", addrs[i]);
	}
	addr_len = strlen (addrs[0]);

	bt_strings = malloc (sizeof (char *) * used);
	pipe_cmd = popen (cmd, "r");
	if (!pipe_cmd) {
		if (pCle==NULL)
			printf ("Cannot fork addr2line to display the backtrace");
		else
			Log (pCle,"Cannot fork addr2line to display the backtrace");
		return;
	}
	for (i = 0; i < used; i++) {
		fgets (line_func, 1024, pipe_cmd);
		line_func[strlen (line_func) - 1] = '\0';
		fgets (line_pos, 1024, pipe_cmd);
		line_pos[strlen (line_pos) - 1] = '\0';
		
#define INFO_MEMOIRE "%s()[%s]"
		Taille_Info_Memoire = strlen (INFO_MEMOIRE) + strlen (line_func) + strlen (line_pos);
		bt_strings[i] = malloc (sizeof (char) * (Taille_Info_Memoire));
		sprintf (bt_strings[i], INFO_MEMOIRE, line_func, line_pos);
		free (addrs[i]);
	}
	pclose (pipe_cmd);
	free (addrs);
	free (the_backtrace);
	free (cmd);
	for (i = 0; i < used; i++){
		if (pCle==NULL)
			printf("%s\n",bt_strings[i]);
		else {
			Log (pCle, bt_strings[i]);
			Log (pCle, "\n");
		}
	}
	if (pCle==NULL)
		printf("-----------------------------\n");
	else
		Log (pCle, "-----------------------------\n");
	
	DEPROTECT_CODE(Semaphore_BackTrace);			
}


void print_trace (void)
{
	void     *array[30];
	size_t    size;
	char    **strings = NULL;
	size_t    i;

	printf ("--- BackTrace ---\n");
	size = backtrace (array, 30);
	strings = backtrace_symbols (array, size);
	for (i = 0; i < size; i++)
		printf ("%s\n", strings[i]);
	free (strings);
}
#endif
