[cfe-dev] Unwind behaviour in Clang/LLVM

Keith Walker Keith.Walker at arm.com
Thu Feb 6 10:02:03 PST 2014


> From: Renato Golin [mailto:renato.golin at linaro.org]
>
> We're having some discussions about the behaviour of exception handling and Dwarf
> sharing unwind logic, tables, etc. and it seems that the code around it wasn't
> designed with any particular goal in mind, but evolved (like the EHABI) and now
> we're seeing the results from it.
>
> The problems below are assuming C vs. C++, but it actually apply to any possibly-exceptional
> vs. never-exceptional cases.
>
>
> 1. C vs. C++
>
> We have two unwind flags: nounwind, which flags functions that can't unwind (leaf,
> nothrow, etc) and uwtable, which forces generation of the table regardless of
> nounwind. It seems sensible that C++ code with exceptions enabled should generate
> the tables for all functions, in case they're called by (or call) external functions.
> In C we don't want any of that.
>
> GCC seems to never emit tables, and G++ always do, even on C code (.c files,
> no exception or anything), which is very sensible and in line with my reasoning above.
> Clang, on the other hand, always generates them. I guess it'll have to figure out what
> to do based on its impressions on what language is being used to produce similar results.

You can make GCC emit unwind tables for C if you use the command line option -funwind-tables.

This could be useful if you are compiling C code which is called by C++ code and which itself calls C++ code and you wish the C++ exception to propagate through the C code.

> I believe that emitting the tables on anything that could potentially interact
> with exceptional code makes sense, but that's clearly a front-end decision.
> To LLVM, nounwind and uwtables should be absolute:

> IF (uwtables)
>  IF (nownwind)
>    CantUnwind
>  ELSE
>    Unwind Table
> ELSE
>   do nothing
> ENDIF

This certainly appears to me a sensible sequence of decision.

> 2. .fnstart/.fnend+friends
>
> Another problem is that the emission of unwinding tables (based on
> .fnstart/.fnend symbols and others) is conditional *only* to the existence
> (or not) of an exception handling class being loaded (EHABI, Dwarf). Which
> means that, we can't disable the EH on a per-function basis.
>
> We'll have to change the way these symbols are emitted, at least when using
> ARMException, so that we can emit the tables and honour the uwtable on a per-function basis.
>
> Again, this is a requirement for problem 1, but it'd need to be fixed after 3.
>
>
> 3. Unwinding code
>
> Currently, even when no exception handling are needed, the exception code is
> used to generate Dwarf unwinding directives (CFI) for the debugger.

This is because the 2 are so similar.

> Both DwarfCFIException and ARMException inherit from DwarfException, and they
> are called to do the debug info about the stack unwinding, which is (at least)
> misplaced. The consensus is that this code should be factored out.

There is some interaction in that if you are generating a .eh_frame section for exception handling then there is little sense is generating a DWARF .debug_frame section as well;  I would hope most debuggers could use the .eh_frame section if present as its format is so similar to a .debug_frame section.

> The part that is relevant to this thread is that, today, if -arm-disable-ehabi
> is requested, ARMException will not be used and we won't have a way of
> generating debug stack directives, which is wrong.

What does -arm-disable-ehabi actually mean?

Currently it is effectively "don't generate exception tables".

Maybe is should it rather be "don't generate EHABI exception tables but generate .eh_frame tables instead"?   Obviously this requires the necessary DWARF like support to generate the information for the .eh_frame tables.

> Factoring out this code is a requirement for the unwinding problem (1), since
> if we disable EH today, we'll disable Dwarf stack unwinding altogether. But we
> also need a final solution for problem 4 below before we start.

I think the solution depends on what we mean when we specify -arm-disable-ehabi ... is it

 IF(arm_disable_ehabi)
   USE ARMException
 ELSE
   USE DwarfCFiNoException   <---- Just generates DWARF debugging information
 ENDIF

Or is it

 IF(arm_disable_ehabi)
   USE ARMException
 ELSE
   USE DwarfCFIException
 ENDIF

> 4. Clang EH control
>
> There are a number of Clang/LLVM options to control exception handling:
>  * -fno-excetpion (enable/disable EH on C++ mode, off in C mode)
>  * -fcxx-exception (no idea, is it objC++ specific? does it control tables in any way?)
>  * -funwind-tables (forces uwtable attribute?)
>  * -arm-disable-ehabi (ARM specific bogus flag)
>
> Those options are not always completely exclusive, and they damage different
> parts of the compilation process (as seen recently on the list), so we need
> a clear consensus on what each option mean (or should mean), and translate it
> to the back-end (via function attributes). This would considerably simplify
> the back-end and help us tackle this refactoring.
>
> My main target for this problem is to have the one true option on the front-ends,
> and rely only on function attributes on the back-end (including tools like llc).
> For that, I'd love to be left with -fexception only and infer all the rest from
> the language / conditions of the code.
>
> Ex:
>
> IF (C++ mode)
>   IF (-fno-exception)
>     no uwtable
>     no nounwind
>   ELSE
>     uwtable
>     IF (leaf / nothrow)
>       nounwind
>     ENDIF
>   ENDIF
> ELSE
>   no uwtable
>   no nounwind
> ENDIF
>
> My main goal is to get rid of (at least) -arm-disable-ehabi.

Hmmm!   I'm very nervous about the backend making decisions based on the language.

As I mentioned above I also wonder if you do still need to support -funwind-tables for compiling C code through which you wish to allow exceptions to propogate.

In which case the logic is more like ....

  IF (-funwind-tables || -fexceptions)
    uwtable
    IF (leaf / nothrow)
      nounwind
    ENDIF
  ELSE
    no uwtable
    no nounwind
  ENDIF

The main difference I see between -fexceptions and -funwind-tables is:

-fexceptions allows compiling exception handling constructs in the source language and enables the generation of unwind tables.
-funwind-tables only enables the generation of unwind tables.

Keith



Keith


-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium.  Thank you.

ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No:  2557590
ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No:  2548782





More information about the cfe-dev mailing list