[Top][All Lists]
[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;
}
- [libunwind] Unwinding using the context passed to a signal handler (doesn't work),
Johan Walles <=