diff --git a/CMakeLists.txt b/CMakeLists.txt index e86120f..80e7fa5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,8 +42,7 @@ libhal_make_library( libhal::util ) -target_compile_definitions(libhal-exceptions PRIVATE - OPTIMIZATION_LEVEL=${OPTIMIZATION_LEVEL}) +target_compile_options(libhal-exceptions PRIVATE -save-temps=obj) if(NOT ${CMAKE_CROSSCOMPILING}) libhal_unit_test( diff --git a/conanfile.py b/conanfile.py index e5162e1..cafde44 100644 --- a/conanfile.py +++ b/conanfile.py @@ -85,19 +85,7 @@ def requirements(self): def build(self): cmake = CMake(self) - optimization_level = { - 'Debug': 1, - 'MinSizeRel': 2, - 'RelWithDebInfo': 3, - 'Release': 4 - } - configure_variables = {"RUNTIME": self._runtime_select} - build_type = self.settings.build_type - if str(build_type) in optimization_level: - configure_variables["OPTIMIZATION_LEVEL"] = optimization_level[str( - build_type)] - cmake.configure(variables=configure_variables) cmake.build() @@ -126,6 +114,7 @@ def package_info(self): if self.options.runtime == "estell": self.cpp_info.exelinkflags.extend([ + "-fexceptions", "-Wl,--wrap=__cxa_throw", "-Wl,--wrap=__cxa_rethrow", "-Wl,--wrap=__cxa_end_catch", diff --git a/src/arm_cortex/estell/exception.cpp b/src/arm_cortex/estell/exception.cpp index 7d631bf..0da6f95 100644 --- a/src/arm_cortex/estell/exception.cpp +++ b/src/arm_cortex/estell/exception.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -24,15 +23,6 @@ #include "internal.hpp" -#define Debug 1 -#define MinSizeRel 2 -#define RelWithDebInfo 3 -#define Release 4 - -#if !defined(OPTIMIZATION_LEVEL) -#error "OPTIMIZATION LEVEL MUST BE DEFINED!" -#endif - namespace ke { union instructions_t @@ -1753,6 +1743,9 @@ void raise_exception(exception_object& p_exception_object) p_exception_object.cache.state(runtime_state::unwind_frame); break; } + if (index_entry.personality_offset == 0x1) { + return; + } p_exception_object.cache.personality = index_entry.personality(); auto const* descriptor_start = index_entry_t::descriptor_start(p_exception_object.cache.personality); @@ -1930,6 +1923,10 @@ void flatten_rtti(ke::exception_ptr p_thrown_exception, } } // namespace ke +namespace { +bool const volatile libhal_convince_compiler_to_emit_metadata = false; +} + extern "C" { void _exit([[maybe_unused]] int rc) // NOLINT @@ -1983,7 +1980,7 @@ extern "C" std::terminate(); } - void __wrap___cxa_rethrow() + void __wrap___cxa_rethrow() noexcept(false) { auto& exception_object = ke::extract_exception_object(ke::active_exception); @@ -1992,30 +1989,16 @@ extern "C" exception_object.cache.state(ke::runtime_state::get_next_frame); exception_object.cache.rethrown(true); - // TODO(35): Replace this with an immediate call to unwind_frame(). What we - // have below is fragile and can break very easily. -#if defined(OPTIMIZATION_LEVEL) - // Perform an inline trivial unwind __cxa_throw: -#if OPTIMIZATION_LEVEL == Debug - std::uint32_t const* stack_pointer = *exception_object.cpu.sp; - exception_object.cpu.r3 = stack_pointer[0]; - exception_object.cpu.pc = stack_pointer[1]; - exception_object.cpu.sp = stack_pointer + 2; -#elif OPTIMIZATION_LEVEL == MinSizeRel - std::uint32_t const* stack_pointer = *exception_object.cpu.sp; - exception_object.cpu.r4 = stack_pointer[0]; - exception_object.cpu.pc = stack_pointer[1]; - exception_object.cpu.sp = stack_pointer + 2; -#elif OPTIMIZATION_LEVEL == Release - std::uint32_t const* stack_pointer = *exception_object.cpu.sp; - exception_object.cpu.r3 = stack_pointer[0]; - exception_object.cpu.pc = stack_pointer[1]; - exception_object.cpu.sp = stack_pointer + 2; -#elif OPTIMIZATION_LEVEL == RelWithDebInfo -#error "Sorry Release mode unwinding is not supported yet."; -#endif -#endif - + // This must ALWAYS evaluate to false. But since the variable is volatile, + // the compiler will not optimize it away and thus, __wrap___cxa_throw will + // require unwind information. This prevents the compiler from optimizing + // the data away. + if (libhal_convince_compiler_to_emit_metadata) { + throw std::bad_alloc(); // What is thrown is not important, just that we + // throw something and since bad_alloc is a MUST + // have in the C++ throw RTTI list, might as well + // reuse it here. + } // Raise exception returns when an error or call to terminate has been found ke::raise_exception(exception_object); // TODO(#38): this area is considered a catch block, meaning that the @@ -2034,35 +2017,20 @@ extern "C" ke::flatten_rtti<12>( p_thrown_exception, exception_object.type_info, p_type_info); - // TODO(35): Replace this with an immediate call to unwind_frame(). What we - // have below is fragile and can break very easily. -#if defined(OPTIMIZATION_LEVEL) - // Perform an inline trivial unwind __cxa_throw: -#if OPTIMIZATION_LEVEL == Debug - std::uint32_t const* stack_pointer = *exception_object.cpu.sp; - exception_object.cpu.r3 = stack_pointer[0]; - exception_object.cpu.r4 = stack_pointer[1]; - exception_object.cpu.r5 = stack_pointer[2]; - exception_object.cpu.pc = stack_pointer[3]; - exception_object.cpu.sp = stack_pointer + 4; -#elif OPTIMIZATION_LEVEL == MinSizeRel -#elif OPTIMIZATION_LEVEL == MinSizeRel - std::uint32_t const* stack_pointer = *exception_object.cpu.sp; - exception_object.cpu.r4 = stack_pointer[0]; - exception_object.cpu.pc = stack_pointer[1]; - exception_object.cpu.sp = stack_pointer + 2; -#elif OPTIMIZATION_LEVEL == Release - std::uint32_t const* stack_pointer = *exception_object.cpu.sp; - exception_object.cpu.r3 = stack_pointer[0]; - exception_object.cpu.pc = stack_pointer[1]; - exception_object.cpu.sp = stack_pointer + 2; -#elif OPTIMIZATION_LEVEL == RelWithDebInfo -#error "Sorry Release mode unwinding is not supported yet."; -#endif -#endif - + // This must ALWAYS evaluate to false. But since the variable is volatile, + // the compiler will not optimize it away and thus, __wrap___cxa_throw will + // require unwind information. This prevents the compiler from optimizing + // the data away. + if (libhal_convince_compiler_to_emit_metadata) { + throw std::bad_alloc(); // What is thrown is not important, just that we + // throw something and since bad_alloc is a MUST + // have in the C++ throw RTTI list, might as well + // reuse it here. + } // Raise exception returns when an error or call to terminate has been found ke::raise_exception(exception_object); + // TODO(#38): this area is considered a catch block, meaning that the + // exception is handled at this point. We should mark it as such. std::terminate(); } -} // extern "C" \ No newline at end of file +} // extern "C" diff --git a/tests/main.test.cpp b/tests/main.test.cpp index 7cb7c4e..19fcfb8 100644 --- a/tests/main.test.cpp +++ b/tests/main.test.cpp @@ -18,4 +18,4 @@ namespace hal { int main() { return 0; -} \ No newline at end of file +}