[LLVMdev] Looking for advice on how to debug a problem with C++ style exception handling code that my compiler generates.

Logan Chien tzuhsiang.chien at gmail.com
Sat Apr 11 20:03:46 PDT 2015


Hi Christian,

Thanks for your explanation.  I know your situation now.  I would suggest
you to check the optimization pass used by the JIT compiler, especially
IPO/PruneEH.cpp.  It will try to add nounwind attribute to functions which
will result in the problem you have mentioned earlier.

Alternatively, as a workaround, try to add uwtable (function attribute) to
the functions that are generated by your compiler.  This may help as well.

Sincerely,
Logan

On Sun, Apr 12, 2015 at 8:49 AM, Christian Schafmeister <
chris.schaf at verizon.net> wrote:

> Logan,
>
> There may be some confusion here because I wasn’t completely clear about
> what was calling what and where “invoke” appeared to be necessary when I
> JIT the code and where I realize that “invoke” is absolutely necessary.
>  As far as I understand the Itanium ABI I only need an “invoke” in function
> A when function B is invoked - the rest of the calls to C() and D() should
> be able to use “call".
>
>
> Here’s an example in C++ (for illustration) and then the identical example
> in Common Lisp.
>
> In Common Lisp I can compile individual expressions in the REPL.
> Here is a more illustrative example.   If I compile all of these functions
> ahead of time - everything works fine and D() and C() are called using LLVM
> “call”.
> But if I JIT these functions one at a time it will fail.  If I use llvm
> “invoke” to JIT the function C() - then the thrown exception will make it
> to A() and everything works.
>
> // In C++
> //
> void D() {
>     throw MyException();
> };
>
> void C() {
>     D();    // This should be able to be called with “call”
> // - but if I JIT this function it won’t work - I need “invoke” and a
> dummy landing pad
> };
>
> void B() {
>     C();    // This can be called with "call"
> };
>
>
> void A() {
>     try {
>         B();     // <<--- This needs to be called with "invoke"
>     } catch ( MyException& e) {
> /* Do something */
>     };
> };
>
>
> In Common Lisp:
>
> (defun d ()
>  (throw 'Exception nil))
>
> (defun c ()
>   (d))    ; <-- This can be called with llvm “call” but if I JIT this
> function it will fail!  I need to use “invoke”!
>
> (defun b ()
>   (c))    ; <-- This can be called with llvm "call"
>
> (defun a ()
>   (catch 'exception
>     (b)))   ; <-- This needs to called with llvm “invoke"
>
>
>
> On Apr 11, 2015, at 8:15 PM, Logan Chien <tzuhsiang.chien at gmail.com>
> wrote:
>
> Hi Christian,
>
> > I don’t see anything in the Itanium ABI that says I need to call the
> function that throws an exception with “invoke” to get exception handling
> to work!
>
> AFAICT, it is the design of LLVM IR and its implementation.  To catch the
> exceptions thrown by the callee functions, we should use the invoke
> instruction along with the landingpad instruction.  If you are calling a
> function with a call instruction, the LLVM backend will simply assumes
> frame unwinding when the callee throws an exception.
>
>
> FYI, according to LLVM reference manual, an invoke-instruction
> <http://llvm.org/docs/LangRef.html#invoke-instruction> has following
> semantics:
>
>> The ‘invoke‘ instruction causes control to transfer to a specified
>> function, with the possibility of control flow transfer to either the ‘
>> normal‘ label or the ‘exception‘ label. If the callee function returns
>> with the “ret” instruction, control flow will return to the “normal”
>> label. If the callee (or any indirect callees) returns via the “*resume*
>> <http://llvm.org/docs/LangRef.html#i-resume>” instruction or other
>> exception handling mechanism, control is interrupted and continued at the
>> dynamically nearest “exception” label.
>>
> OTOH, here's the description for call instruction
> <http://llvm.org/docs/LangRef.html#call-instruction>:
>
>> The ‘call‘ instruction represents a simple function call.
>>
>
> Hope this is helpful.
>
> Best regards,
> Logan
>
> On Sun, Apr 12, 2015 at 6:33 AM, Christian Schafmeister <
> chris.schaf at verizon.net> wrote:
>
>>
>> It appears that I've found a very curious effect where if I JIT a
>> function that throws an exception and I use "call" to call it the throw
>> fails despite there being a "catch" clause on the stack. But if I use
>> “invoke” it works fine!
>>
>>  If I call the function (@cc_invoke) that throws a “core::CatchThrow”
>> exception like this:
>>
>> call void @cc_invoke({ {}*, i64 }* %result-ptr, {}* %3, i64 2, {}* %4, {}* %5, {}* null, {}* null, {}* null)
>> ;; Comment out the next two lines and
>> ;    to label %return0 unwind label %landing-pad1
>> ;return0:
>> ret void
>>
>> landing-pad1:                                     ; No predecessors!
>>   %6 = landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0
>>           cleanup
>>   resume { i8*, i32 } %6
>> }
>>
>>
>> It fails with: libc++abi.dylib: terminating with uncaught exception of
>> type core::CatchThrow
>>
>> If instead I convert the “call” into an “invoke” and hook in a dummy
>> landing-pad like this:
>>
>> invoke void @cc_invoke({ {}*, i64 }* %result-ptr, {}* %3, i64 2, {}* %4, {}* %5, {}* null, {}* null, {}* null)
>>     to label %return0 unwind label %landing-pad1
>> return0:
>>   ret void
>>
>> landing-pad1:                                     ; No predecessors!
>>   %6 = landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0
>>           cleanup
>>   resume { i8*, i32 } %6
>> }
>>
>>
>> The CatchThrow exception is caught and everything works fine!  I don’t
>> need to call the caller or any outer function with “invoke” except for in
>> the function that has the landing pad that recognizes core::CatchThrow.
>>
>> I don’t see anything in the Itanium ABI that says I need to call the
>> function that throws an exception with “invoke” to get exception handling
>> to work!
>>
>> Does anyone have any ideas what I might be doing wrong?
>>
>>
>>
>>
>>
>>
>>
>> On Apr 9, 2015, at 6:59 PM, Lang Hames <lhames at gmail.com> wrote:
>>
>> Hi Christian,
>>
>> Andy's already covered the major points, but you could consider filing a
>> bug at http://llvm.org/bugs too, especially if you've got a small
>> test-case that demonstrates the issue. Exception handling hasn't been a
>> priority in the past, but as more people adopt LLVM's JIT APIs I suspect it
>> will get more attention, and bug reports will help us figure out what needs
>> doing.
>>
>> Cheers,
>> Lang.
>>
>> On Thu, Apr 9, 2015 at 11:43 AM, Kaylor, Andrew <andrew.kaylor at intel.com>
>> wrote:
>>
>>>  Hi Christian,
>>>
>>>
>>>
>>> I suspect that at least some of the details depend on what platform
>>> you’re working on.  I believe that MCJIT attempts to register eh frame
>>> information for either MachO or ELF objects (though for some ELF platforms
>>> nothing actually happens).  What happens to it after that is a darker area,
>>> at least for me.
>>>
>>>
>>>
>>> Apparently there was a GDB command that did just what you want -- “info
>>> catch” -- but I had never used it and it has been removed.  It’s too bad
>>> because it sounds like a nice feature.  It was supposed to dump a list of
>>> catch handlers for whatever frame you’re looking at.  I suspect, however,
>>> that it would have just confirmed that your catch handler isn’t properly
>>> hooked up without being helpful in figuring out why.
>>>
>>>
>>>
>>> You could try debugging the RuntimeDyld code that registers eh frames
>>> and see if that looks right.  RuntimeDyld::registerEHFrames() might be a
>>> helpful starting point.
>>>
>>>
>>>
>>> -Andy
>>>
>>>
>>>
>>>
>>>
>>> *From:* llvmdev-bounces at cs.uiuc.edu [mailto:llvmdev-bounces at cs.uiuc.edu]
>>> *On Behalf Of *Christian Schafmeister
>>> *Sent:* Wednesday, April 08, 2015 10:09 PM
>>> *To:* LLVM Developers Mailing List
>>> *Subject:* [LLVMdev] Looking for advice on how to debug a problem with
>>> C++ style exception handling code that my compiler generates.
>>>
>>>
>>>
>>>
>>>
>>> Hi,
>>>
>>>
>>>
>>> I’m looking for advice on how to debug a problem with my exception
>>> handling code.
>>>
>>> I’m asking a specific question here - but general advice on how to debug
>>> something like this would be greatly appreciated.
>>>
>>>
>>>
>>> Is there any way to get a list of landing pad clauses that are active at
>>> a particular point in a program?
>>> I'd like to get something like a backtrace but listing all active
>>> landing pad clauses. The typeids of the C++ types
>>> I'm trying to debug a problem where an exception that I'm throwing is
>>> not being caught.
>>>
>>> I'm generating JITed code with LLVM and landing pads and I've got shared
>>> libraries - lots of things going on that could potentially be going wrong.
>>>
>>>
>>>
>>> A list of the pointer values like @_ZTIN4core9DynamicGoE is what I’m
>>> looking for.  Then I could compare that to the typeids that I know should
>>> be in that list.
>>>
>>>
>>>
>>> "(TRY-0).landing-pad":                            ; preds =
>>> %"(TRY-0).normal-dest14", %"(TRY-0).tagbody-B-1", %"(TRY-0).normal-dest10",
>>> %"(TRY-0).normal-dest9", %"(TRY-0).normal-dest8", %"(TRY-0).normal-dest",
>>> %"(TRY-0).tagbody-#:G1621-0"
>>>
>>>   %14 = landingpad { i8*, i32 } personality i32 (...)*
>>> @__gxx_personality_v0
>>>
>>>           catch i8* @_ZTIN4core9DynamicGoE
>>>
>>>           catch i8* @_ZTIN4core10ReturnFromE, !dbg !26
>>>
>>>   %15 = extractvalue { i8*, i32 } %14, 0, !dbg !26
>>>
>>>   %16 = extractvalue { i8*, i32 } %14, 1, !dbg !26
>>>
>>>   %17 = call i32 @llvm.eh.typeid.for(i8* @_ZTIN4core9DynamicGoE), !dbg
>>> !26
>>>
>>>   %18 = icmp eq i32 %16, %17, !dbg !26
>>>
>>>   br i1 %18, label %"(TRY-0).handler-block14470", label
>>> %"(TRY-0).dispatch-header19", !dbg !26
>>>
>>>
>>>
>>> I’m getting this error when I throw a core::Unwind exception and I’m
>>> certain that there is a landing pad with that clause.
>>>
>>>
>>>
>>> libc++abi.dylib: terminating with uncaught exception of type core::Unwind
>>>
>>> ../../src/gctools/memoryManagement.cc <http://memorymanagement.cc/>:75
>>> Trapped SIGABRT - starting debugger
>>>
>>> ABORT was called!!!!!!!!!!!!
>>>
>>>
>>>
>>>
>>>
>>> I’ve written a Common Lisp compiler that uses LLVM as the backend and it
>>> interoperates with C++ code and I use C++ exception handling for non-local
>>> exits.
>>>
>>> _______________________________________________
>>> LLVM Developers mailing list
>>> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>>>
>>>
>>
>>
>> _______________________________________________
>> LLVM Developers mailing list
>> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150412/b0ee04b0/attachment.html>


More information about the llvm-dev mailing list