From c09306ffd894f95be195723327d5b17dca73ebd1 Mon Sep 17 00:00:00 2001 From: Felix Rath Date: Fri, 22 May 2020 14:09:10 +0200 Subject: Implemented support for C++ Exceptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We implement the Itanium ABI unwinding base-API, and leave the C++-specific parts to libcxxabi. Co-authored-by: Lukas Wölfer --- lib/Core/ExecutionState.h | 81 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'lib/Core/ExecutionState.h') diff --git a/lib/Core/ExecutionState.h b/lib/Core/ExecutionState.h index 7be69ea7..b3560caf 100644 --- a/lib/Core/ExecutionState.h +++ b/lib/Core/ExecutionState.h @@ -21,6 +21,7 @@ #include "klee/System/Time.h" #include +#include #include #include @@ -63,6 +64,83 @@ struct StackFrame { ~StackFrame(); }; +/// Contains information related to unwinding (Itanium ABI/2-Phase unwinding) +struct UnwindingInformation { + enum class Kind { + SearchPhase, // first phase + CleanupPhase // second phase + }; + +private: + const Kind kind; + +public: + // _Unwind_Exception* of the thrown exception, used in both phases + ref exceptionObject; + + Kind getKind() const { return kind; } + + explicit UnwindingInformation(ref exceptionObject, Kind k) + : kind(k), exceptionObject(exceptionObject) {} + virtual ~UnwindingInformation() = default; + + virtual std::unique_ptr cloned() const = 0; +}; + +struct SearchPhaseUnwindingInformation : public UnwindingInformation { + // Keeps track of the stack index we have so far unwound to. + std::size_t unwindingProgress; + + // MemoryObject that contains a serialized version of the last executed + // landingpad, so we can clean it up after the personality fn returns. + MemoryObject *serializedLandingpad = nullptr; + + SearchPhaseUnwindingInformation(ref exceptionObject, + std::size_t const unwindingProgress) + : UnwindingInformation(exceptionObject, + UnwindingInformation::Kind::SearchPhase), + unwindingProgress(unwindingProgress) {} + + std::unique_ptr cloned() const { + return std::make_unique(*this); + } + + static bool classof(const UnwindingInformation *u) { + return u->getKind() == UnwindingInformation::Kind::SearchPhase; + } +}; + +struct CleanupPhaseUnwindingInformation : public UnwindingInformation { + // Phase 1 will try to find a catching landingpad. + // Phase 2 will unwind up to this landingpad or return from + // _Unwind_RaiseException if none was found. + + // The selector value of the catching landingpad that was found + // during the search phase. + ref selectorValue; + + // Used to know when we have to stop unwinding and to + // ensure that unwinding stops at the frame for which + // we first found a handler in the search phase. + const std::size_t catchingStackIndex; + + CleanupPhaseUnwindingInformation(ref exceptionObject, + ref selectorValue, + const std::size_t catchingStackIndex) + : UnwindingInformation(exceptionObject, + UnwindingInformation::Kind::CleanupPhase), + selectorValue(selectorValue), + catchingStackIndex(catchingStackIndex) {} + + std::unique_ptr cloned() const { + return std::make_unique(*this); + } + + static bool classof(const UnwindingInformation *u) { + return u->getKind() == UnwindingInformation::Kind::CleanupPhase; + } +}; + /// @brief ExecutionState representing a path under exploration class ExecutionState { #ifdef KLEE_UNITTEST @@ -141,6 +219,9 @@ public: /// instruction was covered. std::uint32_t instsSinceCovNew; + /// @brief Keep track of unwinding state while unwinding, otherwise empty + std::unique_ptr unwindingInformation; + /// @brief the global state counter static std::uint32_t nextID; -- cgit 1.4.1