184 lines
7.5 KiB
C
184 lines
7.5 KiB
C
/*
|
|
* sigsegv.h - SIGSEGV signals support
|
|
*
|
|
* Derived from Bruno Haible's work on his SIGSEGV library for clisp
|
|
* <http://clisp.sourceforge.net/>
|
|
*
|
|
* Basilisk II (C) 1997-2008 Christian Bauer
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#ifndef SIGSEGV_H
|
|
#define SIGSEGV_H
|
|
|
|
#define SIGSEGV_MAJOR_VERSION 1
|
|
#define SIGSEGV_MINOR_VERSION 0
|
|
#define SIGSEGV_MICRO_VERSION 0
|
|
|
|
#define SIGSEGV_CHECK_VERSION(MAJOR, MINOR, MICRO) \
|
|
(SIGSEGV_MAJOR_VERSION > (MAJOR) || \
|
|
(SIGSEGV_MAJOR_VERSION == (MAJOR) && SIGSEGV_MINOR_VERSION > (MINOR)) || \
|
|
(SIGSEGV_MAJOR_VERSION == (MAJOR) && SIGSEGV_MINOR_VERSION == (MINOR) && SIGSEGV_MICRO_VERSION >= (MICRO)))
|
|
|
|
// Address type
|
|
typedef char *sigsegv_address_t;
|
|
|
|
// SIGSEGV handler argument (forward declaration)
|
|
|
|
#if HAVE_MACH_EXCEPTIONS
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
extern "C" {
|
|
#include <mach/mach.h>
|
|
#include <mach/mach_error.h>
|
|
}
|
|
|
|
#ifdef __ppc__
|
|
#if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE
|
|
#define MACH_FIELD_NAME(X) __CONCAT(__,X)
|
|
#endif
|
|
#define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state_t
|
|
#define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE
|
|
#define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE_COUNT
|
|
#define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(dar)
|
|
#define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state_t
|
|
#define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE
|
|
#define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
|
|
#define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(srr0)
|
|
#define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
|
|
#define SIGSEGV_REGISTER_FILE (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0)
|
|
#endif
|
|
#ifdef __ppc64__
|
|
#if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE64
|
|
#define MACH_FIELD_NAME(X) __CONCAT(__,X)
|
|
#endif
|
|
#define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state64_t
|
|
#define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE64
|
|
#define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE64_COUNT
|
|
#define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(dar)
|
|
#define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state64_t
|
|
#define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE64
|
|
#define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE64_COUNT
|
|
#define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(srr0)
|
|
#define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
|
|
#define SIGSEGV_REGISTER_FILE (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0)
|
|
#endif
|
|
#ifdef __i386__
|
|
#if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE32
|
|
#define MACH_FIELD_NAME(X) __CONCAT(__,X)
|
|
#endif
|
|
#define SIGSEGV_EXCEPTION_STATE_TYPE i386_exception_state_t
|
|
#define SIGSEGV_EXCEPTION_STATE_FLAVOR i386_EXCEPTION_STATE
|
|
#define SIGSEGV_EXCEPTION_STATE_COUNT i386_EXCEPTION_STATE_COUNT
|
|
#define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(faultvaddr)
|
|
#define SIGSEGV_THREAD_STATE_TYPE i386_thread_state_t
|
|
#define SIGSEGV_THREAD_STATE_FLAVOR i386_THREAD_STATE
|
|
#define SIGSEGV_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
|
|
#define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(eip)
|
|
#define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
|
|
#define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(eax)) /* EAX is the first GPR we consider */
|
|
#endif
|
|
#ifdef __x86_64__
|
|
#if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE64
|
|
#define MACH_FIELD_NAME(X) __CONCAT(__,X)
|
|
#endif
|
|
#define SIGSEGV_EXCEPTION_STATE_TYPE x86_exception_state64_t
|
|
#define SIGSEGV_EXCEPTION_STATE_FLAVOR x86_EXCEPTION_STATE64
|
|
#define SIGSEGV_EXCEPTION_STATE_COUNT x86_EXCEPTION_STATE64_COUNT
|
|
#define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(faultvaddr)
|
|
#define SIGSEGV_THREAD_STATE_TYPE x86_thread_state64_t
|
|
#define SIGSEGV_THREAD_STATE_FLAVOR x86_THREAD_STATE64
|
|
#define SIGSEGV_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
|
|
#define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(rip)
|
|
#define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
|
|
#define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(rax)) /* RAX is the first GPR we consider */
|
|
#endif
|
|
|
|
#ifdef __aarch64__
|
|
#if __DARWIN_UNIX03 && defined _STRUCT_ARM_THREAD_STATE64
|
|
#define MACH_FIELD_NAME(X) __CONCAT(__,X)
|
|
#endif
|
|
#define SIGSEGV_EXCEPTION_STATE_TYPE arm_exception_state64_t
|
|
#define SIGSEGV_EXCEPTION_STATE_FLAVOR ARM_EXCEPTION_STATE64
|
|
#define SIGSEGV_EXCEPTION_STATE_COUNT ARM_EXCEPTION_STATE64_COUNT
|
|
#define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(far)
|
|
#define SIGSEGV_THREAD_STATE_TYPE arm_thread_state64_t
|
|
#define SIGSEGV_THREAD_STATE_FLAVOR ARM_THREAD_STATE64
|
|
#define SIGSEGV_THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT
|
|
#define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(x[0])) /* x[0] is the first GPR we consider */
|
|
#define SIGSEGV_SKIP_INSTRUCTION aarch64_skip_instruction
|
|
#endif
|
|
|
|
#ifdef __x86_64__
|
|
#define SIGSEGV_FAULT_ADDRESS_FAST (((uint64_t)code[1])|0x100000000)
|
|
#else
|
|
#define SIGSEGV_FAULT_ADDRESS_FAST code[1]
|
|
#endif
|
|
#define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_INVALID_ADDRESS
|
|
#define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, mach_exception_data_t code
|
|
#define SIGSEGV_FAULT_HANDLER_ARGS thread, code
|
|
|
|
#endif
|
|
#endif
|
|
|
|
struct sigsegv_info_t {
|
|
sigsegv_address_t addr;
|
|
sigsegv_address_t pc;
|
|
#ifdef HAVE_MACH_EXCEPTIONS
|
|
mach_port_t thread;
|
|
bool has_exc_state;
|
|
SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
|
|
mach_msg_type_number_t exc_state_count;
|
|
bool has_thr_state;
|
|
SIGSEGV_THREAD_STATE_TYPE thr_state;
|
|
mach_msg_type_number_t thr_state_count;
|
|
#endif
|
|
};
|
|
|
|
|
|
// SIGSEGV handler return state
|
|
enum sigsegv_return_t {
|
|
SIGSEGV_RETURN_SUCCESS,
|
|
SIGSEGV_RETURN_FAILURE,
|
|
SIGSEGV_RETURN_SKIP_INSTRUCTION
|
|
};
|
|
|
|
// Type of a SIGSEGV handler. Returns boolean expressing successful operation
|
|
typedef sigsegv_return_t (*sigsegv_fault_handler_t)(sigsegv_info_t *sip);
|
|
|
|
// Type of a SIGSEGV state dump function
|
|
typedef void (*sigsegv_state_dumper_t)(sigsegv_info_t *sip);
|
|
|
|
// Install a SIGSEGV handler. Returns boolean expressing success
|
|
extern bool sigsegv_install_handler(sigsegv_fault_handler_t handler);
|
|
|
|
// Remove the user SIGSEGV handler, revert to default behavior
|
|
extern void sigsegv_uninstall_handler(void);
|
|
|
|
// Set callback function when we cannot handle the fault
|
|
extern void sigsegv_set_dump_state(sigsegv_state_dumper_t handler);
|
|
|
|
// Return the address of the invalid memory reference
|
|
extern sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *sip);
|
|
|
|
// Return the address of the instruction that caused the fault, or
|
|
// SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
|
|
extern sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *sip);
|
|
|
|
// Define an address that is bound to be invalid for a program counter
|
|
const sigsegv_address_t SIGSEGV_INVALID_ADDRESS = sigsegv_address_t(-1);
|
|
|
|
#endif /* SIGSEGV_H */
|