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