[Xbubble-commits] xbubble-sdl/src backtrace.c,NONE,1.1

Martin Quinson mquinson at alioth.debian.org
Mon Sep 11 19:54:48 UTC 2006


Update of /cvsroot/xbubble/xbubble-sdl/src
In directory haydn:/tmp/cvs-serv8858

Added Files:
	backtrace.c 
Log Message:
Current state. Still not working

--- NEW FILE: backtrace.c ---
/* $Id: backtrace.c,v 1.1 2006/09/11 19:54:45 mquinson Exp $ */

/* Backtrace displaying (neat on debugging)                                 */

/* ex - Exception Handling (modified to fit into SimGrid from OSSP version) */

/*  Copyright (c) 2005-2006 Martin Quinson                                  */
/*  All rights reserved.                                                    */

/* This program is free software; you can redistribute it and/or modify it
 * under the terms of the license (GNU LGPL) which comes with this package. */

/* Add this to your configure.ac:
  
AC_CHECK_HEADERS(execinfo.h)
AC_CHECK_FUNCS(popen)
  
AC_PATH_PROG(ADDR2LINE, addr2line)
if test x$ADDR2LINE != x ; then
   AC_DEFINE_UNQUOTED(ADDR2LINE,"$ADDR2LINE",[Path to the addr2line tool])
fi
  
 */ 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> /* getpid() */
#include <unistd.h>


#include "config.h" /* where the result of autoconf lives */
#include "utils.h"  /* where my prototype lives */

#ifdef HAVE_EXECINFO_H
# include <execinfo.h>
#endif

#define MAX_BACKTRACE_SIZE 30

char *binary_name; /* Should be set from argv by main */

void display_backtrace()  {
#if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
  void *bt[MAX_BACKTRACE_SIZE];
  int   used=backtrace((void**)bt,MAX_BACKTRACE_SIZE);
  char **bt_strings=NULL;
   
  int i;
  /* to get the backtrace from the libc */
  char **the_backtrace = backtrace_symbols (bt, used);
  
  /* To build the commandline of addr2line */
  char *cmd = xmalloc(sizeof(char) * (strlen(ADDR2LINE)+strlen(binary_name)+20*used));
  char *curr=cmd;
  
  /* to extract the addresses from the backtrace */
  char **addrs=xmalloc(sizeof(char*)*used);
  char buff[256];
  
  /* To read the output of addr2line */
  FILE *pipe_cmd;
  char line_func[1024],line_pos[1024];

  /* size (in char) of pointers on this arch */
  int addr_len=0;

  /* Some arches only have stubs of backtrace, no implementation (hppa comes to mind) */
  if (!used)
     return;
   
  /* build the commandline */
  curr += sprintf(curr,"%s -f -e %s ", ADDR2LINE, binary_name);
  for (i=0; i<used;i++) {
    char *p;
    /* retrieve this address */
    snprintf(buff,256,"%s",strchr(the_backtrace[i],'[')+1);
    p=strchr(buff,']');
    *p='\0';
    addrs[i]=strdup(buff);
    
    /* Add it to the command line args */
    curr+=sprintf(curr,"%s ",addrs[i]);
  }	 
  addr_len = strlen(addrs[0]);

  /* parse the output and build a new backtrace */
  bt_strings = xmalloc(sizeof(char*) * used);
  
  pipe_cmd = popen(cmd, "r");
  if (!pipe_cmd) {
    fail("Cannot fork addr2line to display the backtrace");
  }
  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';

    if (strcmp("??",line_func)) {
      bt_strings[i] = xmalloc(256);
      sprintf(bt_strings[i], "**   In %s() at %s (static symbol)", line_func,line_pos);
    } else {
      /* Damn. The symbol is in a dynamic library. Let's get wild */
      char *maps_name;
      FILE *maps;
      char maps_buff[512];

      long int addr,offset=0;
      char *p,*p2;

      char *subcmd;
      FILE *subpipe;
      int found=0;

      /* let's look for the offset of this library in our addressing space */
      maps_name=xmalloc(256);
      sprintf(maps_name,"/proc/%d/maps",(int)getpid());
      maps=fopen(maps_name,"r");

      sscanf(addrs[i],"%lx",&addr);
      sprintf(maps_buff,"%#lx",addr);
      
      if (strcmp(addrs[i],maps_buff)) {
	warn("Cannot parse backtrace address '%s' (addr=%#lx)",
		  addrs[i], addr);
      }
      //DEBUG("addr=%s (as string) =%#lx (as number)",addrs[i],addr);

      while (!found) {
	long int first, last;
	if (fgets(maps_buff,512,maps) == NULL) 
	  break;
	if (i==0) {
	  maps_buff[strlen(maps_buff) -1]='\0';
	  //DEBUG("map line: %s", maps_buff);
	}
	sscanf(maps_buff,"%lx",&first);
	p=strchr(maps_buff,'-')+1;
	sscanf(p,"%lx",&last);
	if (first < addr && addr < last) {
	  offset = first;
	  found=1;
	}
	//DEBUG("%#lx %s [%#lx-%#lx]", addr, found? "in":"out of",first,last);
      }
      fclose(maps);
      free(maps_name);

      if (!found) {
	warn("Problem while reading the maps file. Following backtrace will be mangled.");
	bt_strings[i] = strdup(the_backtrace[i]);
	continue;
      }

      /* Ok, Found the offset of the maps line containing the searched symbol. 
	 We now need to substract this from the address we got from backtrace.
      */
      
      free(addrs[i]);
      addrs[i] = xmalloc(256);
      sprintf(addrs[i],"0x%0*lx",addr_len-2,addr-offset);
      //DEBUG("offset=%#lx new addr=%s",offset,addrs[i]);

      /* Got it. We have our new address. Let's get the library path and we are set */ 
      p  = strdup(the_backtrace[i]);
      p2 = strrchr(p,'(');
      if (p2) *p2= '\0';
      p2 = strrchr(p,' ');
      if (p2) *p2= '\0';
      
      /* Here we go, fire an addr2line up */
      subcmd = xmalloc(256);
      sprintf(subcmd,"%s -f -e %s %s",ADDR2LINE,p, addrs[i]);
      free(p);
      //DEBUG("Fire a new command: '%s'",subcmd);
      subpipe = popen(subcmd,"r");
      if (!subpipe) 
	fail("Cannot fork addr2line to display the backtrace");

      fgets(line_func,1024,subpipe);
      line_func[strlen(line_func)-1]='\0';
      fgets(line_pos,1024,subpipe);
      line_pos[strlen(line_pos)-1]='\0';
      pclose(subpipe);
      free(subcmd);

      /* check whether the trick worked */
      if (strcmp("??",line_func)) {
	bt_strings[i] = xmalloc(512);
	sprintf(bt_strings[i],"**   In %s() at %s (dynamic symbol)", line_func,line_pos);
      } else {
	/* damn, nothing to do here. Let's print the raw address */
	bt_strings[i] = xmalloc(512);
	sprintf(bt_strings[i],"**   In ?? (%s)", the_backtrace[i]);
      }
    }
    free(addrs[i]);
  }
  pclose(pipe_cmd);
  free(addrs);
  free(the_backtrace);
  free(cmd);
   
   
  for (i=0; i<used; i++) /* no need to display "display_backtrace" so start at 1 */
    fprintf(stderr,"%s\n",bt_strings[i]);
#else 
  fprintf(stderr,"No backtrace on this arch\n");
#endif
}    




More information about the Xbubble-commits mailing list