libunwind-devel
[Top][All Lists]
Advanced

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

Re: [libunwind] Changing the value of "gp"


From: David Mosberger
Subject: Re: [libunwind] Changing the value of "gp"
Date: Tue, 21 Jan 2003 16:26:04 -0800

Hi Praveen,

>>>>> On Mon, 20 Jan 2003 10:17:19 -0800 (PST), Praveen Vegulla 
>>>>> <address@hidden> said:

  Praveen> Please let me know if I wasn't clear.

Thanks for the explanation.  I think I now understand what you're
trying to do: basically, you're setting up exception handlers
explicitly, but want them to be cancelled automatically, upon
returning from a given function.

  Praveen> The cause of this problem is, in funcC(), I'm calling one
  Praveen> of the libc functions just before return. This changes the
  Praveen> "gp". If funcC() were to return naturally to funcB(), there
  Praveen> is code in funcB() to restore "gp".  But in my
  Praveen> implementation, it jumps to the cleanup function and when
  Praveen> it tries to access the global variable, it craps out since
  Praveen> "gp" is no longer correct for this module.

Yes, that's expected.  When crossing a load-module boundary, there is
a stub which will take care of setting up gp as needed.  I suppose you
could write your own stub which will setup the gp needed by the
exception-handler cleanup routine, but it doesn't strike me as
terribly elegant.

I suppose we could also make it work with a small libunwind/ia64
change.  At the moment, "gp" (r1) is treated as read-only, but if
libunwind were to be changed to allow writing to it, you could do an
exception handler cleanup (cleanup_func()) with something like this:

        - unwind until you reach an IP corresponding to the caller
          of the function that installed the exception handler
        - unw_set_reg (c, UNW_IA64_IP, GET_IP (cleanup_func));
        - unw_set_reg (c, UNW_IA64_GP, GET_GP (cleanup_func));
        - unw_resume (c);

(Assuming the following two macros:

        GET_IP(func) = (((long *) &(func))[0])
        GET_GP(func) = (((long *) &(func))[1])

)

At the end of cleanup-func(), you could then return execution to the
original point (you'd want to restore GP as well as IP, to make sure
things don't break when the caller & callee are known to be in the
same load module).

Caveat 1: this doesn't actually work with the current libunwind
sources because unw_resume() hasn't been fully implemented yet.

Caveat 2: I'm still not comfortable with what's being done here.  It
just seems way too slow and too fragile, as compiler optimizations
could easily causes problems.

If you're willing to manage the exception "stack" in a different
manner, I think a much more efficient and more reliable solution would
be possible:

 o Replace the exception stack with an exception table that maps
   exception-tags to IP values.

 o For SETUP_EXC(tag), simply add to the exception table the IP of the
   call-site for the given "tag".  For example, in gcc you could do
   something along the lines of:

    #define SETUP_EXC(tag)      setup_exc(tag)

    static int
    setup_exc (long tag)
    {
        /* enter caller's IP and the associated tag & handler in the table: */
        exception_table_enter (__builtin_return_address (0), tag);
        return 0;
    }

 o To raise an exception, unwind the stack.  In each frame, check
   whether the code-range for the current frame covers an IP for which
   there is an entry in the exception table.  If so, change "r8" in
   the current frame to 1 and then do an unw_resume() to transfer
   execution to the "exception handler".  It will then appear as if
   SETUP_EXC() returns a second time, except now with a return value
   of 1.

This approach should run much faster and work reliably, provided that
each function associates at most one exception handler with a given
tag.  If you don't want this limitation, you could avoid it by
changing SETUP_EXC(tag) to something like this:

  #define SETUP_EXC(tag)        setup_exc(__FUNCTION__, tag)

This gives setup_exc() a unique tag (the function pointer for the
calling function) with which you can detect when a function re-defines
the handler for a tag.

        --david


reply via email to

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