Solution sought to GCC 4.1.1 backtrace problem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Greetings,

We have a multi-threaded application that runs on an
embedded Linux platform. In the past, the application
was built with a 3.3.2 GNU gcc compiler and ran on a
PXA-based system running Linux 2.4.27. We built a
SEGV signal handler that we armed in each thread's
main() function. This signal handler simply called the
libc backtrace() function.

This scenario worked very well for our device beta
test by non-technical users. Whenever the system
crashed via segv we squirreled away the information on
the device and retrieved it at convenient times,
namely when the device was connected to our server
over a wireless network.

Now, we're moving to a new platform, although it's
still ARM-based, running Linux 2.6.21. Our application
has been ported to GNU GCC 4.1.1. What we have
discovered is that backtrace() doesn't work under
4.1.1, so we can't do the same thing we did under
3.3.2. We found two patches to 4.1.1:

http://gcc.gnu.org/ml/gcc-patches/2006-06/msg00357.html
and
http://www.ecos.sourceware.org/ml/libc-ports/2006-06/msg00045.html

When we applied these patches to gcc 4.1.1,
backtrace() tended to work a little better, but what
we've noticed is that the backtrace is still
inconsistent at unwinding the frame pointer, and the
registers and   program context tended to be those
from the signal handler, which was NOT the case under
3.3.2.

We need a way to fix this problem, if a solution
exists. One solution we tried was to build our own
backtrace() function showed inconsistent results, and
it would be much better if we leveraged the libc
backtrace function. Another solution was to fork gdb
in batch mode in the signal handler, instead of
calling backtrace(). This solution was also
sub-optimal, producing inconsistent backtraces and, in
addition, this requires gdb on the embedded device,
which is space inefficient.

I've included a test program (not muti-threaded) that
we have used to test various solutions.

If you have a solution to this problem, please let us
know. If you need any more information, please let us
know.

Thanks in advance for any assistance you can provide.

-blair


#include <stdio.h>
#include <execinfo.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <execinfo.h>
#include <signal.h>

#include <sigcontextinfo.h>

/* added this to account for the changes to the EABI
frame format in gcc
4.1.1 */
struct layout {
   struct layout *__unbounded next;
   void *__unbounded sp;
   void *__unbounded return_address;
};

int
__arm_backtrace(int **arr, int maxsiz)
{
   int cnt = 0;
   void *fp = __builtin_frame_address (0);
   struct layout *lp = (struct layout *)(fp - 12);
      while (cnt < maxsiz) {
       printf("lp[%d]: %p ra: %p next: %p\n", cnt,
(void *)lp, (void
*)lp->return_address, (void *)lp->next);
       arr[cnt++] = (void *)lp->return_address;
       if (!lp->next) {
           break;
       }
       lp = lp->next - 1;
   }
   return cnt;
}

static void
catch_segfault (int signal, SIGCONTEXT ctx)
{
   int *arr[32];
   int size, i;
   struct sigaction sa;
   char **strings;

   printf("in %s\n", __FUNCTION__);

#ifdef USE_LIBC_BACKTRACE
   size = backtrace((void **)arr, 32);
#else
   size = __arm_backtrace(arr, 32);
#endif
   strings = backtrace_symbols ((void **)arr, size);

   printf ("Obtained %zd stack frames.\n", size);
   for (i = 0; i < size; i++)
       printf ("%s\n", strings[i]);
   free (strings);
      /* Pass on the signal (so that a core file is
produced).  */
   sa.sa_handler = SIG_DFL;
   sigemptyset (&sa.sa_mask);
   sa.sa_flags = 0;
   sigaction (signal, &sa, NULL);
   raise (signal);
}

#define INSTALL_FOR_SIG(sig)     \
       sigaction(sig, &sa, NULL)
void
install_fh(void)
{
   struct sigaction sa;
   char *path = NULL;
   char *where;
      sa.sa_handler = (void *) catch_segfault;
   sigemptyset (&sa.sa_mask);
   sa.sa_flags = SA_RESTART;

   INSTALL_FOR_SIG (SIGSEGV);
}

int
routine4(volatile int arg)
{
   printf("in %s at %.8p\n", __FUNCTION__, routine4);
   *(int *)0 = 0xdeadbeef;
   return 1;
}

int
routine3(volatile int arg)
{
   printf("in %s at %.8p\n", __FUNCTION__, routine3);
   return routine4(0xdead4444);
}

int
routine2(volatile int arg)
{
   printf("in %s at %.8p\n", __FUNCTION__, routine2);
   return routine3(0xdead3333);
}

int
routine1(volatile int arg)
{
   printf("in %s at %.8p\n", __FUNCTION__, routine1)


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux