Exception support in kernel.
Exception support in kernel.
Anyone succeeded in adding C++ exception support to his/her kernel? I tried to port libcxxrt(github.com/pathscale/). libcxxrt itself is very easy to port, it just need libc and a few simple pthread functions. But libcxxrt requires either libunwind or libgcc for stack unwinding. I tried to port libunwind, but found libunwind is horrible to port, it requires lots of posix functions. I haven't tried libgcc, not sure about it. Is libgcc easier to port?
I even tried to implement my own stack unwinding library, but gave up due to lacking of documents.
In case you are new to libcxxrt. libcxxrt is a library developed by pathscale, open sourced recently, distributed under a two-clause BSD license. It's ABI compatible with gcc, can be used to replace libsupc++.
Thanks
-torshie
I even tried to implement my own stack unwinding library, but gave up due to lacking of documents.
In case you are new to libcxxrt. libcxxrt is a library developed by pathscale, open sourced recently, distributed under a two-clause BSD license. It's ABI compatible with gcc, can be used to replace libsupc++.
Thanks
-torshie
Re: Exception support in kernel.
There is a section at the bottom of OS_Specific_Toolchain which discusses getting libsupc++ and libgcc to work for exception handling in the kernel. Again, you have to provide a number of standard c library functions in the kernel as listed in the article (but they aren't too complicated) - the stream writing ones are just for debugging output - as well as declare certain objects in your source. Unfortunately it has been several years since I wrote that article so things may well have changed in more recent gcc versions. I haven't been working on a C++ kernel since then so don't know whether it still works. Hopefully there is someone else around with more recent experience.
Regards,
John.
Regards,
John.
Re: Exception support in kernel.
IIRC, llmv doesn't have a c++ runtime, the compiled binary needs g++ runtime to work.
EDIT: I agree with you that exception is never a must in kernel. But it's just cool to have exception support. Since we just writing our own kernels for fun, why not
EDIT: I agree with you that exception is never a must in kernel. But it's just cool to have exception support. Since we just writing our own kernels for fun, why not
- blobmiester
- Member
- Posts: 45
- Joined: Fri Jul 16, 2010 9:49 am
Re: Exception support in kernel.
Yes, to an extent. I didn't port it though. I've implemented all required methods described in the Itanium C++ ABI [http://www.codesourcery.com/public/cxx-abi/abi.html]. That contains everything you need to know about implementing exception support (as well as typeid and dynamic_cast).
There are two important layers to implementing the exception specification [§4] (there is a third but that is the responsibility of the compiler). The first is the generic unwind interface (or Base) and the second is the C++ interface. The C++ interface is actually quite simple; it's just a few methods that wrap the unwind interface. The unwind interface is (of course) complex but the linked document above should provide sufficient information. If you need any specific help on implementing something in it I'd be glad to assist.
My advice would be to implement RTTI first, as it's miles easier (and required for proper exception handling). I would definitely advise against porting the GCC source. It's an incredible mess. Nearly a 1000 lines in the unwind personality function (madness). Of course they have to support a lot more architectures and environments than I do (but still).
Anyway, hope I helped a bit. Happy coding.
EDIT:
Oops. Forgot to actually say it: I've implemented all C++ runtime support (§18 of the C++ Standard) which includes typeid, exceptions, and dynamic_cast.
There are two important layers to implementing the exception specification [§4] (there is a third but that is the responsibility of the compiler). The first is the generic unwind interface (or Base) and the second is the C++ interface. The C++ interface is actually quite simple; it's just a few methods that wrap the unwind interface. The unwind interface is (of course) complex but the linked document above should provide sufficient information. If you need any specific help on implementing something in it I'd be glad to assist.
My advice would be to implement RTTI first, as it's miles easier (and required for proper exception handling). I would definitely advise against porting the GCC source. It's an incredible mess. Nearly a 1000 lines in the unwind personality function (madness). Of course they have to support a lot more architectures and environments than I do (but still).
Anyway, hope I helped a bit. Happy coding.
EDIT:
Oops. Forgot to actually say it: I've implemented all C++ runtime support (§18 of the C++ Standard) which includes typeid, exceptions, and dynamic_cast.
Re: Exception support in kernel.
You are my hero.blobmiester wrote:Yes, to an extent. I didn't port it though. I've implemented all required methods described in the Itanium C++ ABI [http://www.codesourcery.com/public/cxx-abi/abi.html]. That contains everything you need to know about implementing exception support (as well as typeid and dynamic_cast).
There are two important layers to implementing the exception specification [§4] (there is a third but that is the responsibility of the compiler). The first is the generic unwind interface (or Base) and the second is the C++ interface. The C++ interface is actually quite simple; it's just a few methods that wrap the unwind interface. The unwind interface is (of course) complex but the linked document above should provide sufficient information. If you need any specific help on implementing something in it I'd be glad to assist.
My advice would be to implement RTTI first, as it's miles easier (and required for proper exception handling). I would definitely advise against porting the GCC source. It's an incredible mess. Nearly a 1000 lines in the unwind personality function (madness). Of course they have to support a lot more architectures and environments than I do (but still).
Anyway, hope I helped a bit. Happy coding.
EDIT:
Oops. Forgot to actually say it: I've implemented all C++ runtime support (§18 of the C++ Standard) which includes typeid, exceptions, and dynamic_cast.
Yup, RTTI is really easy to implement, just implement a few trivial classes. I already implemented RTTI before I tried to to port libcxxrt. After porting libcxxrt, I deleted my implementation, because libcxxrt also implemented these classes. As you said, there are two layers to be implemented, for me the C++ interface is implemented in libcxxrt. The missing one is the unwind interface, that's why I want to port libunwind/libgcc. Last night I checked the source code of libgcc_eh.a. Compared with libunwind, libgcc is a true *monster*. So I have to either port libunwind or implement the unwind interface myself. I prefer the latter, because most of the sources are useless to me. I had a stub file to make the kernel compiles with exception enabled.
Code: Select all
#include <unwind.h>
#include <assert.h>
struct ProcessorContext {
unsigned long genericRegister[16];
unsigned long instructionPointer;
};
struct _Unwind_Context {
ProcessorContext processorContext;
};
void _Unwind_Resume(struct _Unwind_Exception*) {
assert(false);
}
_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception*) {
assert(false);
return _URC_FATAL_PHASE1_ERROR;
}
unsigned long _Unwind_GetTextRelBase(struct _Unwind_Context*) {
return 0;
}
unsigned long _Unwind_GetDataRelBase(struct _Unwind_Context *) {
return 0;
}
unsigned long _Unwind_GetLanguageSpecificData(struct _Unwind_Context*) {
return 0;
}
unsigned long _Unwind_GetRegionStart(struct _Unwind_Context*) {
return 0;
}
_Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception* e) {
/* XXX Currently only C++ exception unwinding is supported */
return _Unwind_RaiseException(e);
}
void _Unwind_SetGR(struct _Unwind_Context* context, int index,
unsigned long value) {
context->processorContext.genericRegister[index] = value;
}
void _Unwind_SetIP(struct _Unwind_Context* context, unsigned long value) {
context->processorContext.instructionPointer = value;
}
_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*) {
/* XXX Implement this function.
*
* This function is mainly used for debugging, not a big problem to
* simply return an error.
*/
return _URC_FATAL_PHASE1_ERROR;
}
unsigned long _Unwind_GetIP(struct _Unwind_Context* context) {
return context->processorContext.instructionPointer;
}
Here are my questions:
1. Which information should be stored in the structure _Unwind_Context besides the CPU registers?
2. When and how should the structure _Unwind_Context be initialized?
3. Do I need to port a dwarf parser or I just need to get a copy of dwarf specification and craft my own simple dwarf parser?
BTW, would you mind send me a copy of your own unwind interface implementation?
Thanks in advance.
-torshie
- Owen
- Member
- Posts: 1700
- Joined: Fri Jun 13, 2008 3:21 pm
- Location: Cambridge, United Kingdom
- Contact:
Re: Exception support in kernel.
That depends upon an external implementation of the Itanium C++ ABI. They have not yet reimplemented that.berkus wrote:http://llvm.org/docs/ExceptionHandling.htmltorshie wrote:IIRC, llmv doesn't have a c++ runtime, the compiled binary needs g++ runtime to work.
EDIT: I agree with you that exception is never a must in kernel. But it's just cool to have exception support. Since we just writing our own kernels for fun, why not
Re: Exception support in kernel.
I got some progress on this
Good news:
1. Succeeded in compiling libgcc_eh.a. I extracted the libgcc_eh.a from the native gcc compiler and compiled the corresponding .c files in gcc source tree with my kernel compile system. No source file changes are needed.
2. The kernel compiles with exception support, and exceptions do get caught!
Bad news:
1. Re-throw doesn't work.
2. Exceptions are passed incorrectly.
In the following 3 code fragments, the first one works as expected, the second and the third don't.
Good news:
1. Succeeded in compiling libgcc_eh.a. I extracted the libgcc_eh.a from the native gcc compiler and compiled the corresponding .c files in gcc source tree with my kernel compile system. No source file changes are needed.
2. The kernel compiles with exception support, and exceptions do get caught!
Bad news:
1. Re-throw doesn't work.
2. Exceptions are passed incorrectly.
In the following 3 code fragments, the first one works as expected, the second and the third don't.
Code: Select all
void foo() {
throw 3;
}
void bar() {
try {
foo();
} catch (...) {
printf("Haha, got you!\n");
}
}
Code: Select all
void bar() {
try {
foo();
} catch (int& e) {
printf("%d\n", e); // <======== Incorrect value 1023 printed. *_*
}
}
Code: Select all
// Triple-fault, not haven't debugged, don't know why.
void bar() {
try {
foo();
} catch (...) {
printf("will re-throw\n");
throw;
}
}
void baz() {
try {
bar();
} catch (...) {
printf("Catch re-throw\n");
}
}
Re: Exception support in kernel.
No, why do I need to?berkus wrote:Nice, did you inspect generated .eh_frames?
Re: Exception support in kernel.
Got the problem, I made a stupid mistake in malloc() stub:berkus wrote: Looks like stack unwinding doesn't work properly since you get the wrong values.
Code: Select all
static uintptr_t freeMemoryBase = &base;
void* malloc(size_t size) {
size = Math::roundUp(size, 8);
freeMemoryBase += size;
return (void*)freeMemoryBase;
}
- blobmiester
- Member
- Posts: 45
- Joined: Fri Jul 16, 2010 9:49 am
Re: Exception support in kernel.
Looking very nice torshie.
If that doesn't work, let me see your __cxa_end_catch and __cxa_rethrow implementations.
Remember to not call _Unwind_DeleteException on a rethrow because it would be deleted again (possibly the source of the triple fault).torshie wrote:Re-throw still cause triple fault
If that doesn't work, let me see your __cxa_end_catch and __cxa_rethrow implementations.
Re: Exception support in kernel.
I got the bug, __cxa_end_catch and __cxa_rethrow are OK, they are implemented in libcxxrt. The bug was in my elf loader, the kernel was incorrectly loaded.blobmiester wrote:Looking very nice torshie.Remember to not call _Unwind_DeleteException on a rethrow because it would be deleted again (possibly the source of the triple fault).torshie wrote:Re-throw still cause triple fault
If that doesn't work, let me see your __cxa_end_catch and __cxa_rethrow implementations.
Now I have fully supported C++ exceptions, and I also write a wiki page. http://wiki.osdev.org/C%2B%2B_Exception_Support
Thanks for all the replies.
Re: Exception support in kernel.
Why are you trying to port libgcc? If you build a cross-compiler, you can build libgcc for your target architecture in the process.
-
- Posts: 1
- Joined: Sat May 16, 2015 7:44 am
Re: Exception support in kernel.
How do libcxxrt & libunwind actually tie into each other? I have done searches through the libcxxrt codebase to find instances where the unwind library functions are actually called & used, to no avail. Am I missing something?