Ziqiang Patrick Huang
2015-May-05 14:10 UTC
[LLVMdev] Failed to catch exception across function calls
Dear LLVMers, I'm working on the openrisc backend which is not currently upstreamed, I want to use llvm as the compiler and linking with gcc/g++. I have a simple test program below, right now if I run the compiled binary, it hangs and never returned to the catch block. If I throw exception directly in the try block instead of in another function, it works fine. I've looked at the generated assembly instructions and they all look right to me, except for the generated exception table which I don't know enough to tell whether it's right or nor, my first guess is that maybe there is some compatibility issue for the exception table between llvm and g++, so I try to manually modify according to that generated by g++, but the bug is still there. I wonder how should I approach this issue, is there anything in the backend that could cause the bug ? I attached the assembly in case anyone wants to take a closer look. Any suggestion is greatly appreciated. Patrick #include <stdlib.h> #include <stdio.h> void foo(int a) { throw -15; } int main() { int error = 0; try { foo(0); } catch (int e) { error = e; } printf("Error = %d\n", error); return 0; } -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150505/d45e4120/attachment.html> -------------- next part -------------- A non-text attachment was scrubbed... Name: throw-llvm.s Type: application/octet-stream Size: 3267 bytes Desc: not available URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150505/d45e4120/attachment.obj>
Tim Northover
2015-May-06 03:12 UTC
[LLVMdev] Failed to catch exception across function calls
> I wonder how should I approach this issue, is there anything in the backend > that could cause the bug ?Some cursory research suggests that r1 is the stack pointer on OpenRISC. You seem to be modifying that (& storing callee-saved registers?) but not emitting the required .cfi_XYZ directives to tell the unwinder about those changes. The way exceptions work is that they need extra information to restore the CPU state to what it was in each caller until they reach a catch clause that can handle the exception. This information is provided by each function saying "I changed sp by X, and stored the registers my caller expects to be saved at locations Y, Z and W". It does this via .cfi directives. This is usually handled in XYZFrameLowering.cpp (though I vaguely remember x86 uses a separate pass which re-parses the frame to generate them -- don't quote me on that). I'd suggest searching around for .cfi_def_cfa and .cfi_offset as the most important two: + ".cfi_def_cfa R, off" says "when this function was first called, SP == R + off". + ".cfi_offset R, off" says "to find out what R used to be when the function was first called, load the value at offset "off" from where SP was when this function was called. It's slightly more subtle than that, particularly on CISC architectures (I'd suggest ignoring x86, for example), but that's the essence of it. Hopefully you'll also be able to get the hang of it from what GCC produces. Cheers. Tim.