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: Wed, 24 Mar 2004 10:53:12 +0100
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624

David Mosberger wrote:
On Tue, 23 Mar 2004 13:15:09 +0100, Johan Walles <address@hidden> said:

  Johan> 2. getcontext() on Linux / ia64 returns the context *inside
  Johan> the getcontext() function*, not the context at the place from
  Johan> where getcontext() is called (which is what I always thought
  Johan> it did).

What makes you say this?  The return-pointer is saved in the context,
which is the address of the call-site.

You're just re-phrasing what I said. The fact that it's possible to walk the stack to where getcontext() was called from isn't the same as having getcontext() return the CPU state of the call site. Let's say I have the following program:

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

Inside of foo(), b0 will point to line 7. So a context reflecting the CPU state on line 2 would say "b0 points to line 7". The context I get from getcontext(), says "b0 points to line 3". That's true inside of getcontext(), but it isn't true inside of foo().

Similarly, when executing foo(), the IP will point to line 2. The context I get from the getcontext() call says "the IP is NULL". In my mind that's not a true representation of "the machine-state of the call-site". Obviously this isn't true inside of getcontext() either, but this is worked around in all OS and libunwind code that I know of, so unless people actually look at the context returned by getcontext() this won't be noticable.

  Johan> 3. To compensate for this, unw_init_local() starts by
  Johan> unwinding the context it receives by one frame.

It only does this on HP-UX.

This code snippet from "src/ia64/Ginit-ia64.c" says otherwise:

"
static inline void *
uc_addr (ucontext_t *uc, int reg)
{
  void *addr;

  switch (reg)
    {
    case UNW_IA64_GR + 0:       addr = &unw.r0; break;
    case UNW_IA64_NAT + 0:      addr = &unw.r0; break;
    case UNW_IA64_IP:           addr = &uc->uc_mcontext.sc_br[0]; break;
...
"

Asking for the IP returns b0, not the IP.  Looks like some sort of unwinding to 
me.

The effect of this can also be seen in the attached test program.

So I still maintain that the implementation doesn't match the man-page, and that the implementation should be fixed.

  Cheers //Johan
/*
 * The point of this program is to verify that libunwind skips the
 * first frame of a context when unwinding on Linux / ia64.
 *
 * If the first frame is skipped, it will print 0xbadf00d.
 * If the first frame is accepted, it will print 0x42.
 *
 * The result is that it prints 0xbadf00d, which demonstrates that the
 * first frame gets skipped.
 */

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

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

#define SKIPPED 0xbadf00d
#define NOTSKIPPED 0x42

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";
   }
}

int main(int argc, char *argv[])
{
   ucontext_t context;
   unw_cursor_t cursor;
   unw_word_t ip;
   int r;
   
   memset(&context, 0, sizeof(ucontext_t));
   context.uc_mcontext.sc_ip = NOTSKIPPED;
   context.uc_mcontext.sc_br[0] = SKIPPED;
   
   if ((r = unw_init_local(&cursor, &context)) != 0) {
      fprintf(stderr, "unw_init_local: %s\n", unw_strerror(r));
      exit(EXIT_FAILURE);
   }
   
   if ((r = unw_get_reg(&cursor, UNW_REG_IP, &ip)) != 0) {
      fprintf(stderr, "unw_get_reg: %s\n", unw_strerror(r));
      exit(EXIT_FAILURE);
   }
   
   printf("The unwind cursor says the IP is %p.\n", (void*)ip);
   printf("This means that %s.\n",
          ip == SKIPPED ? "the first frame gets skipped" :
          ip == NOTSKIPPED ? "the first frame doesn't get skipped" :
          "this program is broken");
   
   return 0;
}

reply via email to

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