xref: /aosp_15_r20/external/fbjni/cxx/lyra/lyra_exceptions.h (revision 65c59e023c5336bbd4a23be7af78407e3d80e7e7)
1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <exception>
20 #include <typeinfo>
21 #include <vector>
22 
23 #include <lyra/lyra.h>
24 
25 namespace facebook {
26 namespace lyra {
27 
28 namespace detail {
29 struct ExceptionTraceHolder {
30   ExceptionTraceHolder();
31   // Need some virtual function to make this a polymorphic type.
32   virtual ~ExceptionTraceHolder();
33   ExceptionTraceHolder(const ExceptionTraceHolder&) = delete;
34   ExceptionTraceHolder(ExceptionTraceHolder&&) = default;
35 
36   std::vector<InstructionPointer> stackTrace_;
37 };
38 
39 template <typename E, bool hasTraceHolder>
40 struct Holder : E, ExceptionTraceHolder {
HolderHolder41   Holder(E&& e) : E{std::forward<E>(e)}, ExceptionTraceHolder{} {}
42 };
43 template <typename E>
44 struct Holder<E, true> : E {
45   Holder(E&& e) : E{std::forward<E>(e)} {}
46 };
47 
48 const ExceptionTraceHolder* getExceptionTraceHolder(std::exception_ptr ptr);
49 } // namespace detail
50 
51 /**
52  * Retrieves the stack trace of an exception
53  */
54 const std::vector<InstructionPointer>& getExceptionTrace(
55     std::exception_ptr ptr);
56 
57 /**
58  * Throw an exception and store the stack trace. This works like
59  * std::throw_with_nested in that it will actually throw a type that is
60  * publicly derived from both E and detail::ExceptionTraceHolder.
61  */
62 template <class E>
63 [[noreturn]] void fbthrow(E&& exception) {
64   throw detail::
65       Holder<E, std::is_base_of<detail::ExceptionTraceHolder, E>::value>{
66           std::forward<E>(exception)};
67 }
68 
69 /**
70  * Ensure that a terminate handler that logs traces is installed.
71  * setLibraryIdentifierFunction should be called first if the stack
72  * trace should log build ids for libraries.
73  */
74 void ensureRegisteredTerminateHandler();
75 
76 /**
77  * Helper to convert an exception to a string
78  */
79 std::string toString(std::exception_ptr exceptionPointer);
80 
81 /**
82  * Lyra needs to hook either __cxa_init_primary_exception or __cxa_throw
83  * (depending on the libc++ version) in order to inject stack traces. Users are
84  * required to set up this hooking using the information in this struct:
85  * - original is a pointer to the address of the exception function to hook.
86  *   This pointer should have the address of the unhooked function stored back
87  *   to it (if the hooking mechanism produces it), so that Lyra can delegate to
88  *   the original function.
89  * - replacement is the address of Lyra's replacement function. After the
90  *   hooking, all callers to the original function should call the replacement
91  *   function instead.
92  */
93 struct HookInfo {
94   void** original;
95   void* replacement;
96 };
97 
98 const HookInfo* getHookInfo();
99 
100 void enableCxaThrowHookBacktraces(bool enable);
101 
102 } // namespace lyra
103 } // namespace facebook
104