mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-11-26 10:49:21 +00:00
Improve API for systems that require explicit calls to functions to retrieve
the memory addresses that triggered a SIGSEGV (e.g. MacOS X).
This commit is contained in:
parent
25c5b9599e
commit
902079ec8e
@ -1636,13 +1636,13 @@ static bool arm_skip_instruction(unsigned long * regs)
|
||||
|
||||
// Fallbacks
|
||||
#ifndef SIGSEGV_FAULT_INSTRUCTION
|
||||
#define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
|
||||
#define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_ADDRESS
|
||||
#endif
|
||||
#ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
|
||||
#define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
|
||||
#endif
|
||||
#ifndef SIGSEGV_FAULT_HANDLER_INVOKE
|
||||
#define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) sigsegv_fault_handler(ADDR, IP)
|
||||
#define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
|
||||
#endif
|
||||
|
||||
// SIGSEGV recovery supported ?
|
||||
@ -1655,6 +1655,24 @@ static bool arm_skip_instruction(unsigned long * regs)
|
||||
* SIGSEGV global handler
|
||||
*/
|
||||
|
||||
struct sigsegv_info_t {
|
||||
sigsegv_address_t addr;
|
||||
sigsegv_address_t pc;
|
||||
};
|
||||
|
||||
// Return the address of the invalid memory reference
|
||||
sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *sip)
|
||||
{
|
||||
return sip->addr;
|
||||
}
|
||||
|
||||
// Return the address of the instruction that caused the fault, or
|
||||
// SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
|
||||
sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *sip)
|
||||
{
|
||||
return sip->pc;
|
||||
}
|
||||
|
||||
// This function handles the badaccess to memory.
|
||||
// It is called from the signal handler or the exception handler.
|
||||
static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
|
||||
@ -1670,11 +1688,12 @@ static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
|
||||
MACH_CHECK_ERROR (thread_get_state, krc);
|
||||
#endif
|
||||
|
||||
sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
|
||||
sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
|
||||
sigsegv_info_t si;
|
||||
si.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
|
||||
si.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
|
||||
|
||||
// Call user's handler and reinstall the global handler, if required
|
||||
switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
|
||||
switch (SIGSEGV_FAULT_HANDLER_INVOKE(&si)) {
|
||||
case SIGSEGV_RETURN_SUCCESS:
|
||||
return true;
|
||||
|
||||
@ -1700,7 +1719,7 @@ static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
|
||||
case SIGSEGV_RETURN_FAILURE:
|
||||
// We can't do anything with the fault_address, dump state?
|
||||
if (sigsegv_state_dumper != 0)
|
||||
sigsegv_state_dumper(fault_address, fault_instruction);
|
||||
sigsegv_state_dumper(&si);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2192,8 +2211,10 @@ static volatile int handler_called = 0;
|
||||
static void *b_region, *e_region;
|
||||
#endif
|
||||
|
||||
static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
|
||||
static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
|
||||
{
|
||||
const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
|
||||
const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
|
||||
#if DEBUG
|
||||
printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
|
||||
printf("expected fault at %p\n", page + REF_INDEX);
|
||||
@ -2207,7 +2228,7 @@ static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, si
|
||||
#ifdef __GNUC__
|
||||
// Make sure reported fault instruction address falls into
|
||||
// expected code range
|
||||
if (instruction_address != SIGSEGV_INVALID_PC
|
||||
if (instruction_address != SIGSEGV_INVALID_ADDRESS
|
||||
&& ((instruction_address < (sigsegv_address_t)b_region) ||
|
||||
(instruction_address >= (sigsegv_address_t)e_region)))
|
||||
exit(11);
|
||||
@ -2218,8 +2239,10 @@ static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, si
|
||||
}
|
||||
|
||||
#ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
|
||||
static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
|
||||
static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
|
||||
{
|
||||
const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
|
||||
const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
|
||||
#if DEBUG
|
||||
printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
|
||||
#endif
|
||||
@ -2227,7 +2250,7 @@ static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, si
|
||||
#ifdef __GNUC__
|
||||
// Make sure reported fault instruction address falls into
|
||||
// expected code range
|
||||
if (instruction_address != SIGSEGV_INVALID_PC
|
||||
if (instruction_address != SIGSEGV_INVALID_ADDRESS
|
||||
&& ((instruction_address < (sigsegv_address_t)b_region) ||
|
||||
(instruction_address >= (sigsegv_address_t)e_region)))
|
||||
return SIGSEGV_RETURN_FAILURE;
|
||||
|
@ -24,8 +24,20 @@
|
||||
#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;
|
||||
typedef char *sigsegv_address_t;
|
||||
|
||||
// SIGSEGV handler argument (forward declaration)
|
||||
struct sigsegv_info_t;
|
||||
|
||||
// SIGSEGV handler return state
|
||||
enum sigsegv_return_t {
|
||||
@ -35,10 +47,10 @@ enum sigsegv_return_t {
|
||||
};
|
||||
|
||||
// Type of a SIGSEGV handler. Returns boolean expressing successful operation
|
||||
typedef sigsegv_return_t (*sigsegv_fault_handler_t)(sigsegv_address_t fault_address, sigsegv_address_t instruction_address);
|
||||
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_address_t fault_address, sigsegv_address_t instruction_address);
|
||||
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);
|
||||
@ -49,7 +61,14 @@ 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_PC = (sigsegv_address_t)(-1);
|
||||
const sigsegv_address_t SIGSEGV_INVALID_ADDRESS = (sigsegv_address_t)(-1UL);
|
||||
|
||||
#endif /* SIGSEGV_H */
|
||||
|
Loading…
Reference in New Issue
Block a user