libunwind-devel
[Top][All Lists]
Advanced

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

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


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

David Mosberger wrote:
On Wed, 24 Mar 2004 10:53:12 +0100, Johan Walles <address@hidden> said:

  Johan> 1 foo() {
  Johan> 2   getcontext();
  Johan> 3 }
  Johan> 4
  Johan> 5 main() {
  Johan> 6   foo();
  Johan> 7 }

  Johan> Inside of foo(), b0 will point to line 7.

Wrong.  On _entry_ to foo() b0 will point to line 7.  After the call
to getcontext(), b0 will point to line 3.

My point is that "getcontext(&ctxt); ctxt.uc_mcontext.sc_br[0]" gives me the value 3 that b0 has inside of getcontext(), not the value 7 that b0 has inside of foo() (aka "the call site").

  Johan> case UNW_IA64_IP: addr = &uc->uc_mcontext.sc_br[0]; break;

This says is that the IP of the caller of
getcontext() is stored in sc_br[0].  Could it be stored in sc_ip
instead?  Sure.  What would it change?  Absolutely nothing.

What it would change is that I could then take a signal context that I get from the Linux kernel, fill in the missing registers, pass the result to unw_init_local() and get a complete stack trace, including the first stack frame. If this doesn't matter to you, could you please change it for my sake?

I think the issue here is that we're approaching the whole context handling from different perspectives.

I guess that from your point of view, libunwind is an abstraction layer on top of context structs, and that accesses to all fields in the context should go through libunwind.

From my point of view, libunwind is a secondary way of accessing contexts. For our primary use (of walking Java stacks and throwing exceptions), we have our own unwinding code. Thus, we want to be able to access contexts by directly accessing fields in the struct (be it sigcontext or ucontext_t).

An example of when these views clash is the C program I sent with my last e-mail. If I set the sc_ip in the context to 0x42, pass it to libunwind and ask about the IP I get NULL back. From my perspective, I should have gotten 0x42 back. Had I instead first initialized libunwind with an empty context, set the IP to 0x42 and then asked about it I would have got 0x42 back (as expected), which I imagine is enough from your perspective.

And if JRockits unwinding was entirely libunwind based, that would have been enough for me too.

a signal
context is a very different animal from the ucontext_t returned by
unw_getcontext().  The former captures the "asynchronous state"
(mostly scratch register), the latter the "synchronous state" (mostly
preserved registers).

Another difference is that the Linux kernel puts the IP in the sc_ip field of the sigcontext, but if I understand you correctly the ucontext_t is supposed to have the IP in the sc_br[0] field. This makes it impossible to walk the stack starting from a signal context, with or without the rest of the registers filled in. Libunwind will miss / skip the first frame.

If I re-phrase my question thusly; if I have a signal context, what should I do with it to be able to pass it to libunwind and have libunwind give me all stack frames, including the first one? Filling in all the missing registers doesn't help, as libunwind expects to find the IP in sc_br[0], but the Linux kernel gives me a context where the IP is stored in sc_ip. How do I convert between a struct sigcontext and an ucontext_t?

Could you post an example of how my unwind.c could be modified to do that very conversion correctly?

The attached program has the following output:
"
Here's a stack trace using the signal context with all extra registers filled 
in:
printStackTrace(): Got context at 0x60000fffffff95b0
printStackTrace(): Context sc_ip is 0x40000000000022c0
  0: 0x4000000000002330: main()
  1: 0x200000000008c560: __libc_start_main()
  2: 0x4000000000001420: _start()


Here's a stack trace using the raw signal context:
printStackTrace(): Got context at 0x60000fffffffae20
printStackTrace(): Context sc_ip is 0x40000000000022c0
  0: 0x4000000000002330: main()
  1: 0x200000000008c560: __libc_start_main()
  2: 0x4000000000001420: _start()


Here's a stack trace using the raw signal context with the sc_ip moved to 
sc_br[0]:
printStackTrace(): Got context at 0x60000fffffffa010
printStackTrace(): Context sc_ip is (nil)
  0: 0x40000000000022c0: crash()
unw_step_ptr: Bad register number


Here's a stack trace using an unmodified context from getcontext():
printStackTrace(): Got context at 0x60000fffffff8b50
printStackTrace(): Context sc_ip is (nil)
  0: 0x4000000000001b60: crashhandler()
  1: 0xa0000000000040d0: Unknown
  2: 0x40000000000022c0: crash()
  3: 0x4000000000002330: main()
  4: 0x200000000008c560: __libc_start_main()
  5: 0x4000000000001420: _start()
"

A correct stack trace would have said:
  0: 0x40000000000022c0: crash()
  1: 0x4000000000002330: main()
  2: 0x200000000008c560: __libc_start_main()
  3: 0x4000000000001420: _start()

Using the signal context with all extra registers filled in with values I get from getcontext() doesn't help (which I thought you said it would). If you find any errors in the code for this, it would be *great* if you could point them out to me.

Using the raw signal context doesn't help either (which is what we're debating).

Using the raw signal context, but storing the sc_ip I got from the kernel in sc_br[0] works for the first frame, but then libunwind gets lost.

Using the result of getcontext() works if we skip a few frames.

However, I would *really* want to base the unwinding on the signal context, possibly transformed in any number of ways. How do I convert between from a sigcontext to an ucontext_t? I have added all missing registers, now I want to know *what else* I have to do?

  Regards //Johan

PS: I'm subscribed to the mailing list, so you don't need to include me personally among the recipients.



reply via email to

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