Renato Golin
2014-Mar-19 13:29 UTC
[LLVMdev] Unwind, exception handling, debuggers and profilers
Folks, I'm sorry for getting at this again, but this will not be the last discussion on the topic, so let's just get to business. We're about to merge the last critical patch to make EHABI compatible with other EH mechanisms in LLVM (D3079), and that has unearthed a few issues with the function attributes. Logan's blog post [1] contains a proposal to split unwinding from exceptional logic which I think we should give it a try. I'm trying to make it as backward compatible as possible, but the point is to make the IR authoritative on how and when to emit what kind of unwind information. ** Unwinding ** AFAIK, there are three ways to unwind the stack: 1. Checking the return information on the stack (LR). This might be optimized away, so debuggers and profilers can't rely on it. Binaries with no debug or EH information at all have to resort to this when back-tracing during a segfault or similar. 2. Dwarf unwinding. This is a carefully constructed stack unwinding Dwarf information for each frame that debuggers and profilers can use to gather precise information on the stack, typically stored on .eh_frame sections. 3. Itanium-compatible exception handling. This is another format of unwind tables using personality routines and similar unwinding logic to Dwarf CFI directives, also on .eh_frame. This is why you can use CFI to build the EH tables, and why debuggers can also use this table to unwind the stack. ** Exception Handling ** LLVM has four types of EH: Dwarf, ARM, SjLj and Win64. Of them, only SjLj doesn't need unwind tables, and each of the others, even being Itanium-compatible, need slightly different logic. In LLVM, all targets that use DwarfCFIException are using the same tables as the debugger and profilers would, but ARM and Win64 have separate unwind logic. This is where the problem begins. We're left with three EH types: 1. No tables (SjLj) 2. Dwarf tables (DwarfCFI) 3. Specific EH tables (ARM, Win64?) ** Debug & Profiling ** In debug/profile mode (-g, -pg), none of the optimizations that prune unwind information should be allowed to run. I believe currently this is informed via the uwtable/nothrow function attributes, but since their use is controversial, we can reach situations where information is indeed removed when it shouldn't happen. (see Logan's post). ** Function Attributes Proposal ** I still don't have a clear idea on what do we need, but being overly conservative, we should plan for every behaviour to be expressed by a flag, and during the discussion, merge similar behaviour and possibly remove unused flags along the way. Today we have uwtable and nothrow, which are interchangeably being used to mean debug and EH unwinding, which is just wrong. Logan's proposal is to split uwtable and ehtable, nothrow and nounwind and to understand which trumps which if combined. In my view, nounwind has no purpose. I may be wrong, but I can't think of a case where you want to generate debug unwind tables and NOT want to unwind a particular function on a purely non-EH context. Supposing nounwind has meaning, I'm happy with the semantics Logan proposes in his post. A function without any of the attributes below should emit *no* tables at all. The remaining possibilities are: * uwtable - Generated only when -g or -pg are specified - Option -fno-unwind-tables loses meaning (unless nounwind has meaning) - Generate full EH/Debug tables on all archs * ehtable - Generated for EH only (front-end/arch/lang specific) - Could be forced enabled/disabled via -feh-tables/-fno-eh-tables - Only emits EH directives on ARM, full debug on others, nothing on SjLj * nothrow - Leaf functions, throw(), languages without EH, etc. - On its own, do nothing (no tables are emitted anyway) - +uwtable, do nothing (we don't want to break debug) - +ehtable, emit CantUnwind (the whole purpose) * nounwind - No idea why, but assuming there is a reason - On its own, do nothing (no tables are emitted anyway) - +uwtable, emit CantUnwind (given Logan's semantics) - +ehtable, emit CantUnwind (given Logan's semantics) The primary reason for adding the ehtable attribute is to be able to control the nothrow flag correctly. Other reasons are to limit emitting tables to archs that support it (ie. no SjLj) and to focus -fno-eh-table on EH info only, not Debug, so you don't get broken debug info when you just add "-g" to a build that already has -fno-eh-tables. The option -fno-unwind-tables should either be removed (if nounwind has no meaning apart from EH context), or carefully merged with -fno-eh-tables. Logan can expand on that. The reason why uwtable emits both EH and debug is backwards compatibility. ARM currently emits both directives for binutils' sake, and others have fused Debug/EH directives anyway. This attribute should also prevents any optimization related to stack unwinding, even on recursive or tail calls. LangRef would have to change, but I don't think old IR would stop working. Does that sound like a reasonable plan? Anything I haven't mentioned that needs mentioning? Any conflict that this will generate on any optimization pass? cheers, --renato [1] http://loganchien.github.io/llvm/nounwind.html
Robinson, Paul
2014-Mar-19 21:53 UTC
[LLVMdev] Unwind, exception handling, debuggers and profilers
Just a couple things, I haven't really been following all of the discussion.> Folks, > > I'm sorry for getting at this again, but this will not be the last > discussion on the topic, so let's just get to business. We're about to > merge the last critical patch to make EHABI compatible with other EH > mechanisms in LLVM (D3079), and that has unearthed a few issues with > the function attributes. > > Logan's blog post [1] contains a proposal to split unwinding from > exceptional logic which I think we should give it a try. I'm trying to > make it as backward compatible as possible, but the point is to make > the IR authoritative on how and when to emit what kind of unwind > information. > > ** Unwinding ** > > AFAIK, there are three ways to unwind the stack: > > 1. Checking the return information on the stack (LR). This might be > optimized away, so debuggers and profilers can't rely on it. Binaries > with no debug or EH information at all have to resort to this when > back-tracing during a segfault or similar. > > 2. Dwarf unwinding. This is a carefully constructed stack unwinding > Dwarf information for each frame that debuggers and profilers can use > to gather precise information on the stack, typically stored on > .eh_frame sections. > > 3. Itanium-compatible exception handling. This is another format of > unwind tables using personality routines and similar unwinding logic > to Dwarf CFI directives, also on .eh_frame. This is why you can use > CFI to build the EH tables, and why debuggers can also use this table > to unwind the stack. > > ** Exception Handling ** > > LLVM has four types of EH: Dwarf, ARM, SjLj and Win64. Of them, only > SjLj doesn't need unwind tables, and each of the others, even being > Itanium-compatible, need slightly different logic. > > In LLVM, all targets that use DwarfCFIException are using the same > tables as the debugger and profilers would, but ARM and Win64 have > separate unwind logic. This is where the problem begins. > > We're left with three EH types: > > 1. No tables (SjLj) > 2. Dwarf tables (DwarfCFI) > 3. Specific EH tables (ARM, Win64?) > > ** Debug & Profiling ** > > In debug/profile mode (-g, -pg), none of the optimizations that prune > unwind information should be allowed to run. I believe currently this > is informed via the uwtable/nothrow function attributes, but since > their use is controversial, we can reach situations where information > is indeed removed when it shouldn't happen. (see Logan's post).It is an article of faith among debugger and debug-info people that adding -g must not affect the generated code in any way. Although I have never had to investigate it closely, DWARF unwind info should be able to describe whatever the compiler is willing to produce. And if the program itself will not do unwinding, it's okay for the debug unwind info to be imperfect (see my next comment). Please don't require/assume/imply that -g should disturb optimizations, in particular function attributes that affect optimization should not be present or absent based on -g.> > ** Function Attributes Proposal ** > > I still don't have a clear idea on what do we need, but being overly > conservative, we should plan for every behaviour to be expressed by a > flag, and during the discussion, merge similar behaviour and possibly > remove unused flags along the way. > > Today we have uwtable and nothrow, which are interchangeably being > used to mean debug and EH unwinding, which is just wrong. Logan's > proposal is to split uwtable and ehtable, nothrow and nounwind and to > understand which trumps which if combined. > > In my view, nounwind has no purpose. I may be wrong, but I can't think > of a case where you want to generate debug unwind tables and NOT want > to unwind a particular function on a purely non-EH context. Supposing > nounwind has meaning, I'm happy with the semantics Logan proposes in > his post.Um, does your concept of "unwind" include "debugger displays a backtrace"? A debugger likes to be able to display the chain of subprogram activations that led to the current stopping point (backtrace), but this is different from manipulating the process state to imitate the effect of a sequence of subprogram de-activations (unwind). A debugger also likes to be able to virtually present the process state during some not-the-most-recent activation, which is like a virtual unwind, but this is not a reason to require full EH tables in all cases; this particular debugger feature is well understood by users to be lossy. --paulr> > A function without any of the attributes below should emit *no* tables > at all. > > The remaining possibilities are: > > * uwtable > - Generated only when -g or -pg are specified > - Option -fno-unwind-tables loses meaning (unless nounwind has > meaning) > - Generate full EH/Debug tables on all archs > > * ehtable > - Generated for EH only (front-end/arch/lang specific) > - Could be forced enabled/disabled via -feh-tables/-fno-eh-tables > - Only emits EH directives on ARM, full debug on others, nothing on > SjLj > > * nothrow > - Leaf functions, throw(), languages without EH, etc. > - On its own, do nothing (no tables are emitted anyway) > - +uwtable, do nothing (we don't want to break debug) > - +ehtable, emit CantUnwind (the whole purpose) > > * nounwind > - No idea why, but assuming there is a reason > - On its own, do nothing (no tables are emitted anyway) > - +uwtable, emit CantUnwind (given Logan's semantics) > - +ehtable, emit CantUnwind (given Logan's semantics) > > The primary reason for adding the ehtable attribute is to be able to > control the nothrow flag correctly. Other reasons are to limit > emitting tables to archs that support it (ie. no SjLj) and to focus > -fno-eh-table on EH info only, not Debug, so you don't get broken > debug info when you just add "-g" to a build that already has > -fno-eh-tables. > > The option -fno-unwind-tables should either be removed (if nounwind > has no meaning apart from EH context), or carefully merged with > -fno-eh-tables. Logan can expand on that. > > The reason why uwtable emits both EH and debug is backwards > compatibility. ARM currently emits both directives for binutils' sake, > and others have fused Debug/EH directives anyway. This attribute > should also prevents any optimization related to stack unwinding, even > on recursive or tail calls. > > LangRef would have to change, but I don't think old IR would stop > working. > > Does that sound like a reasonable plan? Anything I haven't mentioned > that needs mentioning? Any conflict that this will generate on any > optimization pass? > > cheers, > --renato > > [1] http://loganchien.github.io/llvm/nounwind.html > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Rafael Espíndola
2014-Mar-20 02:09 UTC
[LLVMdev] Unwind, exception handling, debuggers and profilers
> ** Unwinding ** > > AFAIK, there are three ways to unwind the stack: > > 1. Checking the return information on the stack (LR). This might be > optimized away, so debuggers and profilers can't rely on it. Binaries > with no debug or EH information at all have to resort to this when > back-tracing during a segfault or similar. > > 2. Dwarf unwinding. This is a carefully constructed stack unwinding > Dwarf information for each frame that debuggers and profilers can use > to gather precise information on the stack, typically stored on > .eh_frame sections. > > 3. Itanium-compatible exception handling. This is another format of > unwind tables using personality routines and similar unwinding logic > to Dwarf CFI directives, also on .eh_frame. This is why you can use > CFI to build the EH tables, and why debuggers can also use this table > to unwind the stack.I think this is just 2. It uses .eh_frame for unwinding proper. The only difference in .eh_frame is that there is a personality function defined.> ** Exception Handling ** > > LLVM has four types of EH: Dwarf, ARM, SjLj and Win64. Of them, only > SjLj doesn't need unwind tables, and each of the others, even being > Itanium-compatible, need slightly different logic. > > In LLVM, all targets that use DwarfCFIException are using the same > tables as the debugger and profilers would, but ARM and Win64 have > separate unwind logic. This is where the problem begins. > > We're left with three EH types: > > 1. No tables (SjLj) > 2. Dwarf tables (DwarfCFI) > 3. Specific EH tables (ARM, Win64?) > > ** Debug & Profiling ** > > In debug/profile mode (-g, -pg), none of the optimizations that prune > unwind information should be allowed to run.No. The -g option should never change the set of optimizations that are run. We can add a -Og that means only debug info friendly optimizations, but it should be independent.> A function without any of the attributes below should emit *no* tables at all. > > The remaining possibilities are: > > * uwtable > - Generated only when -g or -pg are specifiedNo. Se above note about -g.> - Option -fno-unwind-tables loses meaning (unless nounwind has meaning) > - Generate full EH/Debug tables on all archs > > * ehtable > - Generated for EH only (front-end/arch/lang specific) > - Could be forced enabled/disabled via -feh-tables/-fno-eh-tables > - Only emits EH directives on ARM, full debug on others, nothing on SjLjSo, I am not really familiar with how we do exception handling, so my only opinion is about the X86-64 abi and LTOing files compiled with and without -fno-asynchronous-unwind-tables. Having a table entry is mandated by the ABI, and -fno-asynchronous-unwind-tables is a non abi conformant option for a user that really knows what it is doing. What we do today then is that on x86-64 "clang -S" adds uwtable to all functions and "clang -S -fno-asynchronous-unwind-tables" doesn't. The net result is that we get tables for the same functions with and without LTO. I would really like to keep this property and this simple logic in the x86 backend.>From previous discussions it seems that the idea was for otherbackends to read it as "make it possible to unwind past this function". It that is not too specific, we could add other attributes, for example: * frame-pointer. Added by the FE when building with -fno-omit-frame-pointer. * arm-unwind-table. The other unwind table format. Cheers, Rafael
Renato Golin
2014-Mar-20 09:33 UTC
[LLVMdev] Unwind, exception handling, debuggers and profilers
On 19 March 2014 21:53, Robinson, Paul <Paul_Robinson at playstation.sony.com> wrote:>> In debug/profile mode (-g, -pg), none of the optimizations that prune >> unwind information should be allowed to run.Sigh... Sorry folks, I made the same mistake *again*. I don't mean to change how passes are run, just to reduce the amount of disturbance in the debug information. I should have said something like: "When -g is set, changes to the unwind information should be preserved more energetically". However, I'm only following Logan's post's ideas, I don't know how much of that is actually possible.> And if > the program itself will not do unwinding, it's okay for the debug > unwind info to be imperfect.Yes, but it has to have at least one way of implying the location of the previous frame, which was the point of my comment.> Um, does your concept of "unwind" include "debugger displays a backtrace"?Yes.> A debugger likes to be able to display the chain of subprogram activations > that led to the current stopping point (backtrace), but this is different > from manipulating the process state to imitate the effect of a sequence of > subprogram de-activations (unwind). > A debugger also likes to be able to virtually present the process state > during some not-the-most-recent activation, which is like a virtual unwind, > but this is not a reason to require full EH tables in all cases; this > particular debugger feature is well understood by users to be lossy.The unwind information in Dwarf / ELF is on the same place EH unwind info is: .eh_frame. The only difference I know is that EH needs the personality routine to find the frame that is catching the exception, while debuggers and profilers only do forced unwind, which only need to know the position of the previous frame, as well as the values of the stack variables on those frames (or in which registers they were, etc). I don't know about the Win64 EH style, but ARM EHABI is not that different! The main differences are: 1. ARM specific unwind directives that GNU implemented almost verbatim, and is what GAS uses to create EH unwind tables on ARM. 2. Short tables, which is a condensed set of stack unwind instructions (1-2 bytes long each) on the word that the pointer to the code in Dwarf would be. None of which actually demand any difference in the IR level. The fact that GNU implemented the ARM directives is also not a reason why we can't use Dwarf CFI directives to encode EHABI logic in the ASM or obj outputs. In a way, we should be moving to use CFI-only for all back-ends. So, in essence, EH tables and debug tables are the same thing. The decision to create a new function attribute is mainly to control how we emit CantUnwind information. cheers, --renato
Renato Golin
2014-Mar-20 09:52 UTC
[LLVMdev] Unwind, exception handling, debuggers and profilers
On 20 March 2014 02:09, Rafael Espíndola <rafael.espindola at gmail.com> wrote:> I think this is just 2. It uses .eh_frame for unwinding proper. The > only difference in .eh_frame is that there is a personality function > defined.If there is no debug information, it should still be possible to unwind the stack via the saved LR on the stack, no? If there is only line info, you could even print the function names with just the LR. But yes, Debug and EH unwinding should be identical (modulo the PR).> No. The -g option should never change the set of optimizations that > are run.Bad wording. I meant fix the edge cases Logan reported on the LR removal, which might have some effect (bigger frames by one word), but that's discussion for another thread.>> * uwtable >> - Generated only when -g or -pg are specified > > No. Se above note about -g.I don't see how not having unwinding information would change the binary execution.> What we do today then is that on x86-64 "clang -S" adds uwtable to all > functions and "clang -S -fno-asynchronous-unwind-tables" doesn't.This is remarkably similar to the behaviour I want to create. But that can't be encoded in IR right now wrt. nothrow. These are the options: 1. no attr: don't emit tables 2. nounwind: emit CantUnwind 3. uwtable: emit table 4. uwtable + nounwind: emit table This is because uwtable means *also* debug/profiler use, and emitting CantUnwind could stop them from unwinding, since there is no information on how to continue unwinding the stack. The semantics I want is to be able to separate between EH unwinding and Debug/Profiler unwinding (even though they map to the same physical tables), so that we DO emit CantUnwind in those cases.> * arm-unwind-table. The other unwind table format.No. This is not an ARM specific issue. The table format is back-end specific, and the IR has no business in interfering with it. cheers, --renato
Possibly Parallel Threads
- [LLVMdev] Unwind, exception handling, debuggers and profilers
- [LLVMdev] Unwind, exception handling, debuggers and profilers
- [LLVMdev] Unwind behaviour in Clang/LLVM
- [LLVMdev] [cfe-dev] Unwind behaviour in Clang/LLVM
- [LLVMdev] [cfe-dev] Unwind behaviour in Clang/LLVM