xref: /openbsd-src/gnu/llvm/compiler-rt/lib/gwp_asan/crash_handler.h (revision 810390e339a5425391477d5d41c78d7cab2424ac)
1d89ec533Spatrick //===-- crash_handler.h -----------------------------------------*- C++ -*-===//
21f9cb04fSpatrick //
31f9cb04fSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41f9cb04fSpatrick // See https://llvm.org/LICENSE.txt for license information.
51f9cb04fSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61f9cb04fSpatrick //
71f9cb04fSpatrick //===----------------------------------------------------------------------===//
81f9cb04fSpatrick 
91f9cb04fSpatrick // This file contains interface functions that can be called by an in-process or
101f9cb04fSpatrick // out-of-process crash handler after the process has terminated. Functions in
111f9cb04fSpatrick // this interface are never thread safe. For an in-process crash handler, the
121f9cb04fSpatrick // handler should call GuardedPoolAllocator::disable() to stop any other threads
131f9cb04fSpatrick // from retrieving new GWP-ASan allocations, which may corrupt the metadata.
141f9cb04fSpatrick #ifndef GWP_ASAN_INTERFACE_H_
151f9cb04fSpatrick #define GWP_ASAN_INTERFACE_H_
161f9cb04fSpatrick 
171f9cb04fSpatrick #include "gwp_asan/common.h"
181f9cb04fSpatrick 
191f9cb04fSpatrick #ifdef __cplusplus
201f9cb04fSpatrick extern "C" {
211f9cb04fSpatrick #endif
221f9cb04fSpatrick 
231f9cb04fSpatrick // When a process crashes, there are three possible outcomes:
241f9cb04fSpatrick //  1. The crash is unrelated to GWP-ASan - in which case this function returns
251f9cb04fSpatrick //     false.
261f9cb04fSpatrick //  2. The crash is internally detected within GWP-ASan itself (e.g. a
271f9cb04fSpatrick //     double-free bug is caught in GuardedPoolAllocator::deallocate(), and
281f9cb04fSpatrick //     GWP-ASan will terminate the process). In this case - this function
291f9cb04fSpatrick //     returns true.
301f9cb04fSpatrick //  3. The crash is caused by a memory error at `AccessPtr` that's caught by the
311f9cb04fSpatrick //     system, but GWP-ASan is responsible for the allocation. In this case -
321f9cb04fSpatrick //     the function also returns true.
331f9cb04fSpatrick // This function takes an optional `AccessPtr` parameter. If the pointer that
341f9cb04fSpatrick // was attempted to be accessed is available, you should provide it here. In the
351f9cb04fSpatrick // case of some internally-detected errors, the crash may manifest as an abort
361f9cb04fSpatrick // or trap may or may not have an associated pointer. In these cases, the
371f9cb04fSpatrick // pointer can be obtained by a call to __gwp_asan_get_internal_crash_address.
381f9cb04fSpatrick bool __gwp_asan_error_is_mine(const gwp_asan::AllocatorState *State,
391f9cb04fSpatrick                               uintptr_t ErrorPtr = 0u);
401f9cb04fSpatrick 
411f9cb04fSpatrick // Diagnose and return the type of error that occurred at `ErrorPtr`. If
421f9cb04fSpatrick // `ErrorPtr` is unrelated to GWP-ASan, or if the error type cannot be deduced,
431f9cb04fSpatrick // this function returns Error::UNKNOWN.
441f9cb04fSpatrick gwp_asan::Error
451f9cb04fSpatrick __gwp_asan_diagnose_error(const gwp_asan::AllocatorState *State,
461f9cb04fSpatrick                           const gwp_asan::AllocationMetadata *Metadata,
471f9cb04fSpatrick                           uintptr_t ErrorPtr);
481f9cb04fSpatrick 
49*810390e3Srobert // This function, provided the fault address from the signal handler, returns
50*810390e3Srobert // the following values:
51*810390e3Srobert //  1. If the crash was caused by an internally-detected error (invalid free,
52*810390e3Srobert //     double free), this function returns the pointer that was used for the
53*810390e3Srobert //     internally-detected bad operation (i.e. the pointer given to free()).
54*810390e3Srobert //  2. For externally-detected crashes (use-after-free, buffer-overflow), this
55*810390e3Srobert //     function returns zero.
56*810390e3Srobert //  3. If GWP-ASan wasn't responsible for the crash at all, this function also
57*810390e3Srobert //     returns zero.
581f9cb04fSpatrick uintptr_t
59*810390e3Srobert __gwp_asan_get_internal_crash_address(const gwp_asan::AllocatorState *State,
60*810390e3Srobert                                       uintptr_t ErrorPtr);
611f9cb04fSpatrick 
621f9cb04fSpatrick // Returns a pointer to the metadata for the allocation that's responsible for
631f9cb04fSpatrick // the crash. This metadata should not be dereferenced directly due to API
641f9cb04fSpatrick // compatibility issues, but should be instead passed to functions below for
651f9cb04fSpatrick // information retrieval. Returns nullptr if there is no metadata available for
661f9cb04fSpatrick // this crash.
671f9cb04fSpatrick const gwp_asan::AllocationMetadata *
681f9cb04fSpatrick __gwp_asan_get_metadata(const gwp_asan::AllocatorState *State,
691f9cb04fSpatrick                         const gwp_asan::AllocationMetadata *Metadata,
701f9cb04fSpatrick                         uintptr_t ErrorPtr);
711f9cb04fSpatrick 
721f9cb04fSpatrick // +---------------------------------------------------------------------------+
731f9cb04fSpatrick // | Error Information Functions                                               |
741f9cb04fSpatrick // +---------------------------------------------------------------------------+
751f9cb04fSpatrick // Functions below return information about the type of error that was caught by
761f9cb04fSpatrick // GWP-ASan, or information about the allocation that caused the error. These
771f9cb04fSpatrick // functions generally take an `AllocationMeta` argument, which should be
781f9cb04fSpatrick // retrieved via. __gwp_asan_get_metadata.
791f9cb04fSpatrick 
801f9cb04fSpatrick // Returns the start of the allocation whose metadata is in `AllocationMeta`.
811f9cb04fSpatrick uintptr_t __gwp_asan_get_allocation_address(
821f9cb04fSpatrick     const gwp_asan::AllocationMetadata *AllocationMeta);
831f9cb04fSpatrick 
841f9cb04fSpatrick // Returns the size of the allocation whose metadata is in `AllocationMeta`
851f9cb04fSpatrick size_t __gwp_asan_get_allocation_size(
861f9cb04fSpatrick     const gwp_asan::AllocationMetadata *AllocationMeta);
871f9cb04fSpatrick 
881f9cb04fSpatrick // Returns the Thread ID that allocated the memory that caused the error at
891f9cb04fSpatrick // `ErrorPtr`. This function may not be called if __gwp_asan_has_metadata()
901f9cb04fSpatrick // returns false.
911f9cb04fSpatrick uint64_t __gwp_asan_get_allocation_thread_id(
921f9cb04fSpatrick     const gwp_asan::AllocationMetadata *AllocationMeta);
931f9cb04fSpatrick 
941f9cb04fSpatrick // Retrieve the allocation trace for the allocation whose metadata is in
951f9cb04fSpatrick // `AllocationMeta`, and place it into the provided `Buffer` that has at least
961f9cb04fSpatrick // `BufferLen` elements. This function returns the number of frames that would
971f9cb04fSpatrick // have been written into `Buffer` if the space was available (i.e. however many
981f9cb04fSpatrick // frames were stored by GWP-ASan). A return value greater than `BufferLen`
991f9cb04fSpatrick // indicates that the trace was truncated when storing to `Buffer`.
1001f9cb04fSpatrick size_t __gwp_asan_get_allocation_trace(
1011f9cb04fSpatrick     const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
1021f9cb04fSpatrick     size_t BufferLen);
1031f9cb04fSpatrick 
1041f9cb04fSpatrick // Returns whether the allocation whose metadata is in `AllocationMeta` has been
1051f9cb04fSpatrick // deallocated. This function may not be called if __gwp_asan_has_metadata()
1061f9cb04fSpatrick // returns false.
1071f9cb04fSpatrick bool __gwp_asan_is_deallocated(
1081f9cb04fSpatrick     const gwp_asan::AllocationMetadata *AllocationMeta);
1091f9cb04fSpatrick 
1101f9cb04fSpatrick // Returns the Thread ID that deallocated the memory whose metadata is in
1111f9cb04fSpatrick // `AllocationMeta`. This function may not be called if
1121f9cb04fSpatrick // __gwp_asan_is_deallocated() returns false.
1131f9cb04fSpatrick uint64_t __gwp_asan_get_deallocation_thread_id(
1141f9cb04fSpatrick     const gwp_asan::AllocationMetadata *AllocationMeta);
1151f9cb04fSpatrick 
1161f9cb04fSpatrick // Retrieve the deallocation trace for the allocation whose metadata is in
1171f9cb04fSpatrick // `AllocationMeta`, and place it into the provided `Buffer` that has at least
1181f9cb04fSpatrick // `BufferLen` elements. This function returns the number of frames that would
1191f9cb04fSpatrick // have been written into `Buffer` if the space was available (i.e. however many
1201f9cb04fSpatrick // frames were stored by GWP-ASan). A return value greater than `BufferLen`
1211f9cb04fSpatrick // indicates that the trace was truncated when storing to `Buffer`. This
1221f9cb04fSpatrick // function may not be called if __gwp_asan_is_deallocated() returns false.
1231f9cb04fSpatrick size_t __gwp_asan_get_deallocation_trace(
1241f9cb04fSpatrick     const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
1251f9cb04fSpatrick     size_t BufferLen);
1261f9cb04fSpatrick 
1271f9cb04fSpatrick #ifdef __cplusplus
1281f9cb04fSpatrick } // extern "C"
1291f9cb04fSpatrick #endif
1301f9cb04fSpatrick 
1311f9cb04fSpatrick #endif // GWP_ASAN_INTERFACE_H_
132