diff osx/include/kj/exception.h @ 62:0994c39f1e94

Cap'n Proto v0.6 + build for OSX
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 22 May 2017 10:01:37 +0100
parents 3ab5a40c4e3b
children
line wrap: on
line diff
--- a/osx/include/kj/exception.h	Mon Mar 06 13:29:58 2017 +0000
+++ b/osx/include/kj/exception.h	Mon May 22 10:01:37 2017 +0100
@@ -1,337 +1,363 @@
-// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
-// Licensed under the MIT License:
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#ifndef KJ_EXCEPTION_H_
-#define KJ_EXCEPTION_H_
-
-#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
-#pragma GCC system_header
-#endif
-
-#include "memory.h"
-#include "array.h"
-#include "string.h"
-
-namespace kj {
-
-class ExceptionImpl;
-
-class Exception {
-  // Exception thrown in case of fatal errors.
-  //
-  // Actually, a subclass of this which also implements std::exception will be thrown, but we hide
-  // that fact from the interface to avoid #including <exception>.
-
-public:
-  enum class Type {
-    // What kind of failure?
-
-    FAILED = 0,
-    // Something went wrong. This is the usual error type. KJ_ASSERT and KJ_REQUIRE throw this
-    // error type.
-
-    OVERLOADED = 1,
-    // The call failed because of a temporary lack of resources. This could be space resources
-    // (out of memory, out of disk space) or time resources (request queue overflow, operation
-    // timed out).
-    //
-    // The operation might work if tried again, but it should NOT be repeated immediately as this
-    // may simply exacerbate the problem.
-
-    DISCONNECTED = 2,
-    // The call required communication over a connection that has been lost. The callee will need
-    // to re-establish connections and try again.
-
-    UNIMPLEMENTED = 3
-    // The requested method is not implemented. The caller may wish to revert to a fallback
-    // approach based on other methods.
-
-    // IF YOU ADD A NEW VALUE:
-    // - Update the stringifier.
-    // - Update Cap'n Proto's RPC protocol's Exception.Type enum.
-  };
-
-  Exception(Type type, const char* file, int line, String description = nullptr) noexcept;
-  Exception(Type type, String file, int line, String description = nullptr) noexcept;
-  Exception(const Exception& other) noexcept;
-  Exception(Exception&& other) = default;
-  ~Exception() noexcept;
-
-  const char* getFile() const { return file; }
-  int getLine() const { return line; }
-  Type getType() const { return type; }
-  StringPtr getDescription() const { return description; }
-  ArrayPtr<void* const> getStackTrace() const { return arrayPtr(trace, traceCount); }
-
-  struct Context {
-    // Describes a bit about what was going on when the exception was thrown.
-
-    const char* file;
-    int line;
-    String description;
-    Maybe<Own<Context>> next;
-
-    Context(const char* file, int line, String&& description, Maybe<Own<Context>>&& next)
-        : file(file), line(line), description(mv(description)), next(mv(next)) {}
-    Context(const Context& other) noexcept;
-  };
-
-  inline Maybe<const Context&> getContext() const {
-    KJ_IF_MAYBE(c, context) {
-      return **c;
-    } else {
-      return nullptr;
-    }
-  }
-
-  void wrapContext(const char* file, int line, String&& description);
-  // Wraps the context in a new node.  This becomes the head node returned by getContext() -- it
-  // is expected that contexts will be added in reverse order as the exception passes up the
-  // callback stack.
-
-  KJ_NOINLINE void extendTrace(uint ignoreCount);
-  // Append the current stack trace to the exception's trace, ignoring the first `ignoreCount`
-  // frames (see `getStackTrace()` for discussion of `ignoreCount`).
-
-  KJ_NOINLINE void truncateCommonTrace();
-  // Remove the part of the stack trace which the exception shares with the caller of this method.
-  // This is used by the async library to remove the async infrastructure from the stack trace
-  // before replacing it with the async trace.
-
-  void addTrace(void* ptr);
-  // Append the given pointer to the backtrace, if it is not already full. This is used by the
-  // async library to trace through the promise chain that led to the exception.
-
-private:
-  String ownFile;
-  const char* file;
-  int line;
-  Type type;
-  String description;
-  Maybe<Own<Context>> context;
-  void* trace[32];
-  uint traceCount;
-
-  friend class ExceptionImpl;
-};
-
-StringPtr KJ_STRINGIFY(Exception::Type type);
-String KJ_STRINGIFY(const Exception& e);
-
-// =======================================================================================
-
-enum class LogSeverity {
-  INFO,      // Information describing what the code is up to, which users may request to see
-             // with a flag like `--verbose`.  Does not indicate a problem.  Not printed by
-             // default; you must call setLogLevel(INFO) to enable.
-  WARNING,   // A problem was detected but execution can continue with correct output.
-  ERROR,     // Something is wrong, but execution can continue with garbage output.
-  FATAL,     // Something went wrong, and execution cannot continue.
-  DBG        // Temporary debug logging.  See KJ_DBG.
-
-  // Make sure to update the stringifier if you add a new severity level.
-};
-
-StringPtr KJ_STRINGIFY(LogSeverity severity);
-
-class ExceptionCallback {
-  // If you don't like C++ exceptions, you may implement and register an ExceptionCallback in order
-  // to perform your own exception handling.  For example, a reasonable thing to do is to have
-  // onRecoverableException() set a flag indicating that an error occurred, and then check for that
-  // flag just before writing to storage and/or returning results to the user.  If the flag is set,
-  // discard whatever you have and return an error instead.
-  //
-  // ExceptionCallbacks must always be allocated on the stack.  When an exception is thrown, the
-  // newest ExceptionCallback on the calling thread's stack is called.  The default implementation
-  // of each method calls the next-oldest ExceptionCallback for that thread.  Thus the callbacks
-  // behave a lot like try/catch blocks, except that they are called before any stack unwinding
-  // occurs.
-
-public:
-  ExceptionCallback();
-  KJ_DISALLOW_COPY(ExceptionCallback);
-  virtual ~ExceptionCallback() noexcept(false);
-
-  virtual void onRecoverableException(Exception&& exception);
-  // Called when an exception has been raised, but the calling code has the ability to continue by
-  // producing garbage output.  This method _should_ throw the exception, but is allowed to simply
-  // return if garbage output is acceptable.
-  //
-  // The global default implementation throws an exception unless the library was compiled with
-  // -fno-exceptions, in which case it logs an error and returns.
-
-  virtual void onFatalException(Exception&& exception);
-  // Called when an exception has been raised and the calling code cannot continue.  If this method
-  // returns normally, abort() will be called.  The method must throw the exception to avoid
-  // aborting.
-  //
-  // The global default implementation throws an exception unless the library was compiled with
-  // -fno-exceptions, in which case it logs an error and returns.
-
-  virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
-                          String&& text);
-  // Called when something wants to log some debug text.  `contextDepth` indicates how many levels
-  // of context the message passed through; it may make sense to indent the message accordingly.
-  //
-  // The global default implementation writes the text to stderr.
-
-protected:
-  ExceptionCallback& next;
-
-private:
-  ExceptionCallback(ExceptionCallback& next);
-
-  class RootExceptionCallback;
-  friend ExceptionCallback& getExceptionCallback();
-};
-
-ExceptionCallback& getExceptionCallback();
-// Returns the current exception callback.
-
-KJ_NOINLINE KJ_NORETURN(void throwFatalException(kj::Exception&& exception, uint ignoreCount = 0));
-// Invoke the exception callback to throw the given fatal exception.  If the exception callback
-// returns, abort.
-
-KJ_NOINLINE void throwRecoverableException(kj::Exception&& exception, uint ignoreCount = 0);
-// Invoke the exception callback to throw the given recoverable exception.  If the exception
-// callback returns, return normally.
-
-// =======================================================================================
-
-namespace _ { class Runnable; }
-
-template <typename Func>
-Maybe<Exception> runCatchingExceptions(Func&& func) noexcept;
-// Executes the given function (usually, a lambda returning nothing) catching any exceptions that
-// are thrown.  Returns the Exception if there was one, or null if the operation completed normally.
-// Non-KJ exceptions will be wrapped.
-//
-// If exception are disabled (e.g. with -fno-exceptions), this will still detect whether any
-// recoverable exceptions occurred while running the function and will return those.
-
-class UnwindDetector {
-  // Utility for detecting when a destructor is called due to unwind.  Useful for:
-  // - Avoiding throwing exceptions in this case, which would terminate the program.
-  // - Detecting whether to commit or roll back a transaction.
-  //
-  // To use this class, either inherit privately from it or declare it as a member.  The detector
-  // works by comparing the exception state against that when the constructor was called, so for
-  // an object that was actually constructed during exception unwind, it will behave as if no
-  // unwind is taking place.  This is usually the desired behavior.
-
-public:
-  UnwindDetector();
-
-  bool isUnwinding() const;
-  // Returns true if the current thread is in a stack unwind that it wasn't in at the time the
-  // object was constructed.
-
-  template <typename Func>
-  void catchExceptionsIfUnwinding(Func&& func) const;
-  // Runs the given function (e.g., a lambda).  If isUnwinding() is true, any exceptions are
-  // caught and treated as secondary faults, meaning they are considered to be side-effects of the
-  // exception that is unwinding the stack.  Otherwise, exceptions are passed through normally.
-
-private:
-  uint uncaughtCount;
-
-  void catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const;
-};
-
-namespace _ {  // private
-
-class Runnable {
-public:
-  virtual void run() = 0;
-};
-
-template <typename Func>
-class RunnableImpl: public Runnable {
-public:
-  RunnableImpl(Func&& func): func(kj::mv(func)) {}
-  void run() override {
-    func();
-  }
-private:
-  Func func;
-};
-
-Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept;
-
-}  // namespace _ (private)
-
-template <typename Func>
-Maybe<Exception> runCatchingExceptions(Func&& func) noexcept {
-  _::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func));
-  return _::runCatchingExceptions(runnable);
-}
-
-template <typename Func>
-void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const {
-  if (isUnwinding()) {
-    _::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func));
-    catchExceptionsAsSecondaryFaults(runnable);
-  } else {
-    func();
-  }
-}
-
-#define KJ_ON_SCOPE_SUCCESS(code) \
-  ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
-  KJ_DEFER(if (!KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
-// Runs `code` if the current scope is exited normally (not due to an exception).
-
-#define KJ_ON_SCOPE_FAILURE(code) \
-  ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
-  KJ_DEFER(if (KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
-// Runs `code` if the current scope is exited due to an exception.
-
-// =======================================================================================
-
-KJ_NOINLINE ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount);
-// Attempt to get the current stack trace, returning a list of pointers to instructions. The
-// returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace.
-// If the platform doesn't support stack traces, returns an empty array.
-//
-// `ignoreCount` items will be truncated from the front of the trace. This is useful for chopping
-// off a prefix of the trace that is uninteresting to the developer because it's just locations
-// inside the debug infrastructure that is requesting the trace. Be careful to mark functions as
-// KJ_NOINLINE if you intend to count them in `ignoreCount`. Note that, unfortunately, the
-// ignored entries will still waste space in the `space` array (and the returned array's `begin()`
-// is never exactly equal to `space.begin()` due to this effect, even if `ignoreCount` is zero
-// since `getStackTrace()` needs to ignore its own internal frames).
-
-String stringifyStackTrace(ArrayPtr<void* const>);
-// Convert the stack trace to a string with file names and line numbers. This may involve executing
-// suprocesses.
-
-void printStackTraceOnCrash();
-// Registers signal handlers on common "crash" signals like SIGSEGV that will (attempt to) print
-// a stack trace. You should call this as early as possible on program startup. Programs using
-// KJ_MAIN get this automatically.
-
-kj::StringPtr trimSourceFilename(kj::StringPtr filename);
-// Given a source code file name, trim off noisy prefixes like "src/" or
-// "/ekam-provider/canonical/".
-
-}  // namespace kj
-
-#endif  // KJ_EXCEPTION_H_
+// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
+// Licensed under the MIT License:
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef KJ_EXCEPTION_H_
+#define KJ_EXCEPTION_H_
+
+#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
+#pragma GCC system_header
+#endif
+
+#include "memory.h"
+#include "array.h"
+#include "string.h"
+
+namespace kj {
+
+class ExceptionImpl;
+
+class Exception {
+  // Exception thrown in case of fatal errors.
+  //
+  // Actually, a subclass of this which also implements std::exception will be thrown, but we hide
+  // that fact from the interface to avoid #including <exception>.
+
+public:
+  enum class Type {
+    // What kind of failure?
+
+    FAILED = 0,
+    // Something went wrong. This is the usual error type. KJ_ASSERT and KJ_REQUIRE throw this
+    // error type.
+
+    OVERLOADED = 1,
+    // The call failed because of a temporary lack of resources. This could be space resources
+    // (out of memory, out of disk space) or time resources (request queue overflow, operation
+    // timed out).
+    //
+    // The operation might work if tried again, but it should NOT be repeated immediately as this
+    // may simply exacerbate the problem.
+
+    DISCONNECTED = 2,
+    // The call required communication over a connection that has been lost. The callee will need
+    // to re-establish connections and try again.
+
+    UNIMPLEMENTED = 3
+    // The requested method is not implemented. The caller may wish to revert to a fallback
+    // approach based on other methods.
+
+    // IF YOU ADD A NEW VALUE:
+    // - Update the stringifier.
+    // - Update Cap'n Proto's RPC protocol's Exception.Type enum.
+  };
+
+  Exception(Type type, const char* file, int line, String description = nullptr) noexcept;
+  Exception(Type type, String file, int line, String description = nullptr) noexcept;
+  Exception(const Exception& other) noexcept;
+  Exception(Exception&& other) = default;
+  ~Exception() noexcept;
+
+  const char* getFile() const { return file; }
+  int getLine() const { return line; }
+  Type getType() const { return type; }
+  StringPtr getDescription() const { return description; }
+  ArrayPtr<void* const> getStackTrace() const { return arrayPtr(trace, traceCount); }
+
+  struct Context {
+    // Describes a bit about what was going on when the exception was thrown.
+
+    const char* file;
+    int line;
+    String description;
+    Maybe<Own<Context>> next;
+
+    Context(const char* file, int line, String&& description, Maybe<Own<Context>>&& next)
+        : file(file), line(line), description(mv(description)), next(mv(next)) {}
+    Context(const Context& other) noexcept;
+  };
+
+  inline Maybe<const Context&> getContext() const {
+    KJ_IF_MAYBE(c, context) {
+      return **c;
+    } else {
+      return nullptr;
+    }
+  }
+
+  void wrapContext(const char* file, int line, String&& description);
+  // Wraps the context in a new node.  This becomes the head node returned by getContext() -- it
+  // is expected that contexts will be added in reverse order as the exception passes up the
+  // callback stack.
+
+  KJ_NOINLINE void extendTrace(uint ignoreCount);
+  // Append the current stack trace to the exception's trace, ignoring the first `ignoreCount`
+  // frames (see `getStackTrace()` for discussion of `ignoreCount`).
+
+  KJ_NOINLINE void truncateCommonTrace();
+  // Remove the part of the stack trace which the exception shares with the caller of this method.
+  // This is used by the async library to remove the async infrastructure from the stack trace
+  // before replacing it with the async trace.
+
+  void addTrace(void* ptr);
+  // Append the given pointer to the backtrace, if it is not already full. This is used by the
+  // async library to trace through the promise chain that led to the exception.
+
+private:
+  String ownFile;
+  const char* file;
+  int line;
+  Type type;
+  String description;
+  Maybe<Own<Context>> context;
+  void* trace[32];
+  uint traceCount;
+
+  friend class ExceptionImpl;
+};
+
+StringPtr KJ_STRINGIFY(Exception::Type type);
+String KJ_STRINGIFY(const Exception& e);
+
+// =======================================================================================
+
+enum class LogSeverity {
+  INFO,      // Information describing what the code is up to, which users may request to see
+             // with a flag like `--verbose`.  Does not indicate a problem.  Not printed by
+             // default; you must call setLogLevel(INFO) to enable.
+  WARNING,   // A problem was detected but execution can continue with correct output.
+  ERROR,     // Something is wrong, but execution can continue with garbage output.
+  FATAL,     // Something went wrong, and execution cannot continue.
+  DBG        // Temporary debug logging.  See KJ_DBG.
+
+  // Make sure to update the stringifier if you add a new severity level.
+};
+
+StringPtr KJ_STRINGIFY(LogSeverity severity);
+
+class ExceptionCallback {
+  // If you don't like C++ exceptions, you may implement and register an ExceptionCallback in order
+  // to perform your own exception handling.  For example, a reasonable thing to do is to have
+  // onRecoverableException() set a flag indicating that an error occurred, and then check for that
+  // flag just before writing to storage and/or returning results to the user.  If the flag is set,
+  // discard whatever you have and return an error instead.
+  //
+  // ExceptionCallbacks must always be allocated on the stack.  When an exception is thrown, the
+  // newest ExceptionCallback on the calling thread's stack is called.  The default implementation
+  // of each method calls the next-oldest ExceptionCallback for that thread.  Thus the callbacks
+  // behave a lot like try/catch blocks, except that they are called before any stack unwinding
+  // occurs.
+
+public:
+  ExceptionCallback();
+  KJ_DISALLOW_COPY(ExceptionCallback);
+  virtual ~ExceptionCallback() noexcept(false);
+
+  virtual void onRecoverableException(Exception&& exception);
+  // Called when an exception has been raised, but the calling code has the ability to continue by
+  // producing garbage output.  This method _should_ throw the exception, but is allowed to simply
+  // return if garbage output is acceptable.
+  //
+  // The global default implementation throws an exception unless the library was compiled with
+  // -fno-exceptions, in which case it logs an error and returns.
+
+  virtual void onFatalException(Exception&& exception);
+  // Called when an exception has been raised and the calling code cannot continue.  If this method
+  // returns normally, abort() will be called.  The method must throw the exception to avoid
+  // aborting.
+  //
+  // The global default implementation throws an exception unless the library was compiled with
+  // -fno-exceptions, in which case it logs an error and returns.
+
+  virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
+                          String&& text);
+  // Called when something wants to log some debug text.  `contextDepth` indicates how many levels
+  // of context the message passed through; it may make sense to indent the message accordingly.
+  //
+  // The global default implementation writes the text to stderr.
+
+  enum class StackTraceMode {
+    FULL,
+    // Stringifying a stack trace will attempt to determine source file and line numbers. This may
+    // be expensive. For example, on Linux, this shells out to `addr2line`.
+    //
+    // This is the default in debug builds.
+
+    ADDRESS_ONLY,
+    // Stringifying a stack trace will only generate a list of code addresses.
+    //
+    // This is the default in release builds.
+
+    NONE
+    // Generating a stack trace will always return an empty array.
+    //
+    // This avoids ever unwinding the stack. On Windows in particular, the stack unwinding library
+    // has been observed to be pretty slow, so exception-heavy code might benefit significantly
+    // from this setting. (But exceptions should be rare...)
+  };
+
+  virtual StackTraceMode stackTraceMode();
+  // Returns the current preferred stack trace mode.
+
+protected:
+  ExceptionCallback& next;
+
+private:
+  ExceptionCallback(ExceptionCallback& next);
+
+  class RootExceptionCallback;
+  friend ExceptionCallback& getExceptionCallback();
+};
+
+ExceptionCallback& getExceptionCallback();
+// Returns the current exception callback.
+
+KJ_NOINLINE KJ_NORETURN(void throwFatalException(kj::Exception&& exception, uint ignoreCount = 0));
+// Invoke the exception callback to throw the given fatal exception.  If the exception callback
+// returns, abort.
+
+KJ_NOINLINE void throwRecoverableException(kj::Exception&& exception, uint ignoreCount = 0);
+// Invoke the exception callback to throw the given recoverable exception.  If the exception
+// callback returns, return normally.
+
+// =======================================================================================
+
+namespace _ { class Runnable; }
+
+template <typename Func>
+Maybe<Exception> runCatchingExceptions(Func&& func) noexcept;
+// Executes the given function (usually, a lambda returning nothing) catching any exceptions that
+// are thrown.  Returns the Exception if there was one, or null if the operation completed normally.
+// Non-KJ exceptions will be wrapped.
+//
+// If exception are disabled (e.g. with -fno-exceptions), this will still detect whether any
+// recoverable exceptions occurred while running the function and will return those.
+
+class UnwindDetector {
+  // Utility for detecting when a destructor is called due to unwind.  Useful for:
+  // - Avoiding throwing exceptions in this case, which would terminate the program.
+  // - Detecting whether to commit or roll back a transaction.
+  //
+  // To use this class, either inherit privately from it or declare it as a member.  The detector
+  // works by comparing the exception state against that when the constructor was called, so for
+  // an object that was actually constructed during exception unwind, it will behave as if no
+  // unwind is taking place.  This is usually the desired behavior.
+
+public:
+  UnwindDetector();
+
+  bool isUnwinding() const;
+  // Returns true if the current thread is in a stack unwind that it wasn't in at the time the
+  // object was constructed.
+
+  template <typename Func>
+  void catchExceptionsIfUnwinding(Func&& func) const;
+  // Runs the given function (e.g., a lambda).  If isUnwinding() is true, any exceptions are
+  // caught and treated as secondary faults, meaning they are considered to be side-effects of the
+  // exception that is unwinding the stack.  Otherwise, exceptions are passed through normally.
+
+private:
+  uint uncaughtCount;
+
+  void catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const;
+};
+
+namespace _ {  // private
+
+class Runnable {
+public:
+  virtual void run() = 0;
+};
+
+template <typename Func>
+class RunnableImpl: public Runnable {
+public:
+  RunnableImpl(Func&& func): func(kj::mv(func)) {}
+  void run() override {
+    func();
+  }
+private:
+  Func func;
+};
+
+Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept;
+
+}  // namespace _ (private)
+
+template <typename Func>
+Maybe<Exception> runCatchingExceptions(Func&& func) noexcept {
+  _::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func));
+  return _::runCatchingExceptions(runnable);
+}
+
+template <typename Func>
+void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const {
+  if (isUnwinding()) {
+    _::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func));
+    catchExceptionsAsSecondaryFaults(runnable);
+  } else {
+    func();
+  }
+}
+
+#define KJ_ON_SCOPE_SUCCESS(code) \
+  ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
+  KJ_DEFER(if (!KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
+// Runs `code` if the current scope is exited normally (not due to an exception).
+
+#define KJ_ON_SCOPE_FAILURE(code) \
+  ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
+  KJ_DEFER(if (KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
+// Runs `code` if the current scope is exited due to an exception.
+
+// =======================================================================================
+
+KJ_NOINLINE ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount);
+// Attempt to get the current stack trace, returning a list of pointers to instructions. The
+// returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace.
+// If the platform doesn't support stack traces, returns an empty array.
+//
+// `ignoreCount` items will be truncated from the front of the trace. This is useful for chopping
+// off a prefix of the trace that is uninteresting to the developer because it's just locations
+// inside the debug infrastructure that is requesting the trace. Be careful to mark functions as
+// KJ_NOINLINE if you intend to count them in `ignoreCount`. Note that, unfortunately, the
+// ignored entries will still waste space in the `space` array (and the returned array's `begin()`
+// is never exactly equal to `space.begin()` due to this effect, even if `ignoreCount` is zero
+// since `getStackTrace()` needs to ignore its own internal frames).
+
+String stringifyStackTrace(ArrayPtr<void* const>);
+// Convert the stack trace to a string with file names and line numbers. This may involve executing
+// suprocesses.
+
+String getStackTrace();
+// Get a stack trace right now and stringify it. Useful for debugging.
+
+void printStackTraceOnCrash();
+// Registers signal handlers on common "crash" signals like SIGSEGV that will (attempt to) print
+// a stack trace. You should call this as early as possible on program startup. Programs using
+// KJ_MAIN get this automatically.
+
+kj::StringPtr trimSourceFilename(kj::StringPtr filename);
+// Given a source code file name, trim off noisy prefixes like "src/" or
+// "/ekam-provider/canonical/".
+
+}  // namespace kj
+
+#endif  // KJ_EXCEPTION_H_