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