libunwind-devel
[Top][All Lists]
Advanced

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

[libunwind] Unwinding using the context passed to a signal handler (does


From: Johan Walles
Subject: [libunwind] Unwinding using the context passed to a signal handler (doesn't work)
Date: Wed, 17 Mar 2004 16:18:45 +0100
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624

Hi!

I'm trying to create a stack dump from inside a signal handler. The context I'm using is the one passed as the third parameter to the signal handler. I'm doing this on Linux / ia64 using libunwind 0.96.

I built my program using:

  gcc -Wall -Werror -g unwind.c -o unwind -lunwind

What the attached program does is basically this:
1. Register a SIGSEGV handler.
2. Call a function that triggers a SIGSEGV.
3. In the signal handler:
3.1. Pass the context received in the third parameter to unw_init_local(), and walk the stack from there. 3.2. Fetch a context from the OS using getcontext(), pass that context to unw_init_local() and walk the stack from there.

This is the output from the program:
"
printStackTrace(): Got context at 0x60000fffffffae50
  0: 0x4000000000001f30: main()
  1: 0x200000000008c560: __libc_start_main()
  2: 0x4000000000001500: _start()
printStackTrace(): Got context at 0x60000fffffffa310
  0: 0x4000000000001ce0: crashhandler()
  1: 0xa0000000000040d0: Unknown
  2: 0x4000000000001ec0: crash()
  3: 0x4000000000001f30: main()
  4: 0x200000000008c560: __libc_start_main()
  5: 0x4000000000001500: _start()
"

Note that the function that crashes (crash()) isn't part of the first stack trace (initialized using the context passed to the signal handler).

Why isn't it? And if I want that, what should I do? Am I using libunwind correctly?

  Cheers //Johan
/*
 * The point of this program is to verify a bad behaviour of
 * libunwind on ia64:
 * 
 * 1. Unwinding starting from a context received by a signal handler
 *   misses the first (?) frame.
 * 2. Unwinding starting from a context returned by calling
 *   getcontext() inside the signal handler succeeds.
 */

#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <ucontext.h>
#include <assert.h>

#define UNW_LOCAL_ONLY
#include "libunwind-ia64.h"

static const char *
unw_strerror(int err)
{
   if (err < 0) {
      err = -err;
   }
   switch (err) {
   case UNW_ESUCCESS:       return "No error";
   case UNW_EUNSPEC:        return "Unspecified (general) error";
   case UNW_ENOMEM:         return "Out of memory";
   case UNW_EBADREG:        return "Bad register number";
   case UNW_EREADONLYREG:   return "Attempt to write read-only register";
   case UNW_ESTOPUNWIND:    return "Stop unwinding";
   case UNW_EINVALIDIP:     return "Invalid IP";
   case UNW_EBADFRAME:      return "Bad frame";
   case UNW_EINVAL:         return "Unsupported operation or bad value";
   case UNW_EBADVERSION:    return "Unwind info has unsupported version";
   case UNW_ENOINFO:        return "No unwind info found";
   default:                 return "Unknown error";
   }
}

static void printStackTrace(struct sigcontext *context)
{
   unw_cursor_t cursor;
   unw_word_t ip, off;
   char name[64];
   int r, count = 0;

   printf("%s(): Got context at %p\n", __FUNCTION__, context);
   
   if ((r = unw_init_local(&cursor, (ucontext_t *)context)) != 0) {
      fprintf(stderr, "unw_init_local: %s\n", unw_strerror(r));
      exit(EXIT_FAILURE);
   }
   
   do {
      unw_get_reg(&cursor, UNW_REG_IP, &ip);
      if ((r = unw_get_proc_name(&cursor, name, sizeof(name), &off)) == 0) {
         printf("%3d: %p: %s()\n", count, (void*)ip, name);
      } else {
         printf("%3d: %p: Unknown\n", count, (void*)ip);
      }
      
      r = unw_step(&cursor);
      count++;
   } while (r > 0);
   
   if (r < 0) {
       fprintf(stderr, "unw_step_ptr: %s\n", unw_strerror(r));
       exit(EXIT_FAILURE);
   }
}

void crashhandler(int signo, siginfo_t *siginfo, void *contextAsVoid)
{
   int result;
   ucontext_t localContext;
   struct sigcontext *crashContext = (struct sigcontext *)contextAsVoid;
   
   // Protect against recursive crashing
   signal(signo, SIG_DFL);
   
   assert(signo == SIGSEGV);

   // Print a stack trace showing the state at the time of the crash
   printStackTrace(crashContext);

   // Fetch our current context
   result = getcontext(&localContext);
   assert(result == 0);

   // Print a stack trace showing where we are currently
   printStackTrace(&localContext.uc_mcontext);

   printf("%s(): Bye!\n", __FUNCTION__);
   exit(EXIT_SUCCESS);
}

void setUpCrashHandler()
{
   int result;
   struct sigaction action;
   
   action.sa_sigaction = crashhandler;
   sigfillset(&action.sa_mask);
   action.sa_flags = SA_SIGINFO;
   
   result = sigaction(SIGSEGV, &action, NULL);
   assert(result == 0);
}

void crash()
{
   volatile int i = *(int*)7;
   (void)i;
}

int main(int argc, char *argv[])
{
   setUpCrashHandler();
   crash();
   
   return 0;
}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]