discuss-gnustep
[Top][All Lists]
Advanced

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

Re: eh_personality.c in libobjc2


From: Mathias Bauer
Subject: Re: eh_personality.c in libobjc2
Date: Wed, 05 Mar 2014 15:30:34 +0100
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:24.0) Gecko/20100101 Thunderbird/24.3.0

Hi David,

I didn't know that posting GPL snippets is a problem, I will avoid it in the future. Sorry for that. As always - IANAL. ;-)

I was investigating phase 1, and indeed IMHO we need to search the LSDA in phase 1 on ARM. Also, in case we don't find one, we have to adjust the context (means: the VRS in ARM speech) so that "virtual" unwinding can continue with the next frame. That's what I understood from the spec.

Before I start probably implementing that and before I also investigate what we might need to do in phase 2, I wanted to see if someone else can point out some flaws in my analysis so far. I want to avoid to invest even more time for implementing something, that at the end is not needed.

I will come back with comments to phase 2 later, but in case somebody else has some input to the topic, I would be interested to read that.

Regards,
Mathias

Am 05.03.14 15:13, schrieb David Chisnall:
Hi Mathias,

I had to stop reading your email once it became clear that you had posted code 
snippets to GPLv3 code.

The EH personality function on ARM has not been very well tested, and I 
currently don't have a working ARM box to test it with, so patches and comments 
are very welcome, but please avoid posting GPLv3 code (e.g. the libgcc 
unwinder), because that makes it difficult for me to continue reading.

 From your early description, it sounds like we need to search the LSDA until 
we find a catch in phase 1, even if we find a cleanup first, is that correct?  
Do we also need to visit the cleanup, or do we assume catches supersede 
cleanups?

David

On 5 Mar 2014, at 13:52, Mathias Bauer <mathias_bauer@gmx.net> wrote:

Hi dear list members,

as already reported here, libobjc2 and the latest exception handling produced 
by clang 3.5pre builds an ARM don't work together well. In all but trivial 
cases it ends up in an endless loop.

I investigated the unwinder code in gcc for both ARM and DWARF EHABI. From what 
I saw there and from what I see in the personality routine of libobjc2, I see a 
possible reason why this doesn't go together well.

OTOH I assume that exception handling on ARM usually works on gcc builds with 
libobjc2 (does it?), so I'm unsure how to align that with my findings. Maybe 
myfindings are wrong, so if someone that better than me, please help me 
understanding that better.

Here's what I believe is going on:

The ARM EHABI spec states:
(http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf)

Finally the unwinder calls the PR, passing state
_US_VIRTUAL_UNWIND_FRAME, the UCB pointer, and an _Unwind_Context
pointer for VRS access.
The PR must discover whether this frame contains a propagation
barrier to the exception object, by examining the EHT entry, pointed
to from the UCB pr_cache. It must also adjust the VRS as necessary by
calling functions in the language-independent unwinding library. It
returns to _Unwind_RaiseException with one of:
- Barrier found (_URC_HANDLER_FOUND)
- No barrier (_URC_CONTINUE_UNWIND)
- Error (_URC_FAILURE)

Consequently, this is what the ARM unwinder does (unwind-arm.c in gcc):

  /* Unwind until we reach a propagation barrier.  */
  do
    {
      /* Find the entry for this routine.  */
      if (get_eit_entry (ucbp, saved_vrs.core.r[R_PC]) != _URC_OK)
        return _URC_FAILURE;

      /* Call the pr to decide what to do.  */
      pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
        (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs);
    }
  while (pr_result == _URC_CONTINUE_UNWIND);

So what happens in the personality routine? (eh_personality.c, function 
"internal_objc_personality"):

The first thing that the PR does wrong is that it does not examine the whole frames' 
data, only the current context. If that is a cleanup, the PR will stop there and return 
_URC_CONTINUE_UNWIND. But according to the spec it should check the whole frame for a 
"barrier" (a catch handler) and return _URC_HANDLER_FOUND if it found one.

Only if the frame does not contain such a handler, the return code 
_URC_CONTINUE_UNWIND would be correct, but in that case the personality routine 
had to do something more, as stated in the ARM EHABI spec:

_URC_CONTINUE_UNWIND indicates that no applicable propagation barrier
was found in the function. Before returning, the PR is required to
have done a virtual unwind by updating the VRS to reflect the machine
state at the call to the current function.

But the PR in eh_personality.c does not do that.

So in case the current context points to a cleanup, neither the unwinder nor 
the personality routine will change any data. The PR will return 
_URC_CONTINUE_UNWIND and will be called by the unwinder again and again with 
the same input data. It's obvious that this will create an endless loop.

The PR obviously does only what it needs to support the DWARF unwinder:
(http://mentorembedded.github.io/cxx-abi/abi-eh.html)

In the search phase, the framework repeatedly calls the personality
routine, with the _UA_SEARCH_PHASE flag as described below, first for
the current PC and register state, and then unwinding a frame to a
new PC at each step, until the personality routine reports either
success (a handler found in the queried frame) or failure (no
handler) in all frames.

So the DWARF unwinder does this (undwind.inc in gcc):

  /* Phase 1: Search.  Unwind the stack, calling the personality routine
     with the _UA_SEARCH_PHASE flag set.  Do not modify the stack yet.  */
  while (1)
    {
      _Unwind_FrameState fs;

      /* Set up fs to describe the FDE for the caller of cur_context.  The
         first time through the loop, that means __cxa_throw.  */
      code = uw_frame_state_for (&cur_context, &fs);

      if (code == _URC_END_OF_STACK)
        /* Hit end of stack with no handler found.  */
        return _URC_END_OF_STACK;

      if (code != _URC_NO_REASON)
        /* Some error encountered.  Usually the unwinder doesn't
           diagnose these and merely crashes.  */
        return _URC_FATAL_PHASE1_ERROR;

      /* Unwind successful.  Run the personality routine, if any.  */
      if (fs.personality)
        {
          code = (*fs.personality) (1, _UA_SEARCH_PHASE, exc->exception_class,
                                    exc, &cur_context);
          if (code == _URC_HANDLER_FOUND)
            break;
          else if (code != _URC_CONTINUE_UNWIND)
            return _URC_FATAL_PHASE1_ERROR;
        }

      /* Update cur_context to describe the same frame as fs.  */
      uw_update_context (&cur_context, &fs);
    }

Now the PR does not need to do anything with the context if it points to a 
cleanup, as the unwinder takes care of updating the context after each call to 
the personality routine.

It seems that we have to change the personality routine to support the ARM 
EHABI spec.

Comments welcome.

Regards,
Mathias

_______________________________________________
Discuss-gnustep mailing list
Discuss-gnustep@gnu.org
https://lists.gnu.org/mailman/listinfo/discuss-gnustep




-- Sent from my STANTEC-ZEBRA




reply via email to

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