10 |
|
* tjw@omnigroup.com Sun, 4 Jun 2000 |
11 |
|
* www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html |
12 |
|
* |
13 |
< |
* Basilisk II (C) 1997-2005 Christian Bauer |
13 |
> |
* Basilisk II (C) 1997-2008 Christian Bauer |
14 |
|
* |
15 |
|
* This program is free software; you can redistribute it and/or modify |
16 |
|
* it under the terms of the GNU General Public License as published by |
70 |
|
enum transfer_type_t { |
71 |
|
SIGSEGV_TRANSFER_UNKNOWN = 0, |
72 |
|
SIGSEGV_TRANSFER_LOAD = 1, |
73 |
< |
SIGSEGV_TRANSFER_STORE = 2, |
73 |
> |
SIGSEGV_TRANSFER_STORE = 2 |
74 |
|
}; |
75 |
|
|
76 |
|
// Transfer size |
79 |
|
SIZE_BYTE, |
80 |
|
SIZE_WORD, // 2 bytes |
81 |
|
SIZE_LONG, // 4 bytes |
82 |
< |
SIZE_QUAD, // 8 bytes |
82 |
> |
SIZE_QUAD // 8 bytes |
83 |
|
}; |
84 |
|
|
85 |
< |
#if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__)) |
85 |
> |
#if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__)) |
86 |
|
// Addressing mode |
87 |
|
enum addressing_mode_t { |
88 |
|
MODE_UNKNOWN, |
602 |
|
} |
603 |
|
|
604 |
|
#ifdef __ppc__ |
605 |
+ |
#define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state_t |
606 |
+ |
#define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE |
607 |
+ |
#define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE_COUNT |
608 |
+ |
#define SIGSEGV_FAULT_ADDRESS SIP->exc_state.dar |
609 |
|
#define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state_t |
610 |
|
#define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE |
611 |
|
#define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT |
612 |
< |
#define SIGSEGV_FAULT_INSTRUCTION state->srr0 |
612 |
> |
#define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.srr0 |
613 |
|
#define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction |
614 |
< |
#define SIGSEGV_REGISTER_FILE (unsigned long *)&state->srr0, (unsigned long *)&state->r0 |
614 |
> |
#define SIGSEGV_REGISTER_FILE (unsigned long *)&SIP->thr_state.srr0, (unsigned long *)&SIP->thr_state.r0 |
615 |
> |
#endif |
616 |
> |
#ifdef __ppc64__ |
617 |
> |
#define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state64_t |
618 |
> |
#define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE64 |
619 |
> |
#define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE64_COUNT |
620 |
> |
#define SIGSEGV_FAULT_ADDRESS SIP->exc_state.dar |
621 |
> |
#define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state64_t |
622 |
> |
#define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE64 |
623 |
> |
#define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE64_COUNT |
624 |
> |
#define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.srr0 |
625 |
> |
#define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction |
626 |
> |
#define SIGSEGV_REGISTER_FILE (unsigned long *)&SIP->thr_state.srr0, (unsigned long *)&SIP->thr_state.r0 |
627 |
|
#endif |
628 |
|
#ifdef __i386__ |
629 |
< |
#ifdef i386_SAVED_STATE |
630 |
< |
#define SIGSEGV_THREAD_STATE_TYPE struct i386_saved_state |
631 |
< |
#define SIGSEGV_THREAD_STATE_FLAVOR i386_SAVED_STATE |
632 |
< |
#define SIGSEGV_THREAD_STATE_COUNT i386_SAVED_STATE_COUNT |
617 |
< |
#define SIGSEGV_REGISTER_FILE ((unsigned long *)&state->edi) /* EDI is the first GPR we consider */ |
618 |
< |
#else |
629 |
> |
#define SIGSEGV_EXCEPTION_STATE_TYPE struct i386_exception_state |
630 |
> |
#define SIGSEGV_EXCEPTION_STATE_FLAVOR i386_EXCEPTION_STATE |
631 |
> |
#define SIGSEGV_EXCEPTION_STATE_COUNT i386_EXCEPTION_STATE_COUNT |
632 |
> |
#define SIGSEGV_FAULT_ADDRESS SIP->exc_state.faultvaddr |
633 |
|
#define SIGSEGV_THREAD_STATE_TYPE struct i386_thread_state |
634 |
|
#define SIGSEGV_THREAD_STATE_FLAVOR i386_THREAD_STATE |
635 |
|
#define SIGSEGV_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT |
636 |
< |
#define SIGSEGV_REGISTER_FILE ((unsigned long *)&state->eax) /* EAX is the first GPR we consider */ |
636 |
> |
#define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.eip |
637 |
> |
#define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction |
638 |
> |
#define SIGSEGV_REGISTER_FILE ((unsigned long *)&SIP->thr_state.eax) /* EAX is the first GPR we consider */ |
639 |
|
#endif |
640 |
< |
#define SIGSEGV_FAULT_INSTRUCTION state->eip |
640 |
> |
#ifdef __x86_64__ |
641 |
> |
#define SIGSEGV_EXCEPTION_STATE_TYPE struct x86_exception_state64 |
642 |
> |
#define SIGSEGV_EXCEPTION_STATE_FLAVOR x86_EXCEPTION_STATE64 |
643 |
> |
#define SIGSEGV_EXCEPTION_STATE_COUNT x86_EXCEPTION_STATE64_COUNT |
644 |
> |
#define SIGSEGV_FAULT_ADDRESS SIP->exc_state.faultvaddr |
645 |
> |
#define SIGSEGV_THREAD_STATE_TYPE struct x86_thread_state64 |
646 |
> |
#define SIGSEGV_THREAD_STATE_FLAVOR x86_THREAD_STATE64 |
647 |
> |
#define SIGSEGV_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT |
648 |
> |
#define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.rip |
649 |
|
#define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction |
650 |
+ |
#define SIGSEGV_REGISTER_FILE ((unsigned long *)&SIP->thr_state.rax) /* RAX is the first GPR we consider */ |
651 |
|
#endif |
652 |
< |
#define SIGSEGV_FAULT_ADDRESS code[1] |
653 |
< |
#define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) ((code[0] == KERN_PROTECTION_FAILURE || code[0] == KERN_INVALID_ADDRESS) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE) |
654 |
< |
#define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, exception_data_t code, SIGSEGV_THREAD_STATE_TYPE *state |
655 |
< |
#define SIGSEGV_FAULT_HANDLER_ARGS thread, code, &state |
652 |
> |
#define SIGSEGV_FAULT_ADDRESS_FAST code[1] |
653 |
> |
#define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_INVALID_ADDRESS |
654 |
> |
#define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, exception_data_t code |
655 |
> |
#define SIGSEGV_FAULT_HANDLER_ARGS thread, code |
656 |
|
|
657 |
|
// Since there can only be one exception thread running at any time |
658 |
|
// this is not a problem. |
810 |
|
#endif |
811 |
|
#if defined(__APPLE__) && defined(__MACH__) |
812 |
|
enum { |
813 |
+ |
#if (defined(i386) || defined(__i386__)) |
814 |
|
#ifdef i386_SAVED_STATE |
815 |
|
// same as FreeBSD (in Open Darwin 8.0.1) |
816 |
|
X86_REG_EIP = 10, |
827 |
|
X86_REG_EIP = 10, |
828 |
|
X86_REG_EAX = 0, |
829 |
|
X86_REG_ECX = 2, |
830 |
< |
X86_REG_EDX = 4, |
830 |
> |
X86_REG_EDX = 3, |
831 |
|
X86_REG_EBX = 1, |
832 |
|
X86_REG_ESP = 7, |
833 |
|
X86_REG_EBP = 6, |
834 |
|
X86_REG_ESI = 5, |
835 |
|
X86_REG_EDI = 4 |
836 |
|
#endif |
837 |
+ |
#endif |
838 |
+ |
#if defined(__x86_64__) |
839 |
+ |
X86_REG_R8 = 8, |
840 |
+ |
X86_REG_R9 = 9, |
841 |
+ |
X86_REG_R10 = 10, |
842 |
+ |
X86_REG_R11 = 11, |
843 |
+ |
X86_REG_R12 = 12, |
844 |
+ |
X86_REG_R13 = 13, |
845 |
+ |
X86_REG_R14 = 14, |
846 |
+ |
X86_REG_R15 = 15, |
847 |
+ |
X86_REG_EDI = 4, |
848 |
+ |
X86_REG_ESI = 5, |
849 |
+ |
X86_REG_EBP = 6, |
850 |
+ |
X86_REG_EBX = 1, |
851 |
+ |
X86_REG_EDX = 3, |
852 |
+ |
X86_REG_EAX = 0, |
853 |
+ |
X86_REG_ECX = 2, |
854 |
+ |
X86_REG_ESP = 7, |
855 |
+ |
X86_REG_EIP = 16 |
856 |
+ |
#endif |
857 |
|
}; |
858 |
|
#endif |
859 |
|
#if defined(_WIN32) |
1161 |
|
#endif |
1162 |
|
|
1163 |
|
// Decode and skip PPC instruction |
1164 |
< |
#if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__)) |
1164 |
> |
#if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__)) |
1165 |
|
static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs) |
1166 |
|
{ |
1167 |
|
instruction_t instr; |
1636 |
|
|
1637 |
|
|
1638 |
|
// Fallbacks |
1639 |
+ |
#ifndef SIGSEGV_FAULT_ADDRESS_FAST |
1640 |
+ |
#define SIGSEGV_FAULT_ADDRESS_FAST SIGSEGV_FAULT_ADDRESS |
1641 |
+ |
#endif |
1642 |
+ |
#ifndef SIGSEGV_FAULT_INSTRUCTION_FAST |
1643 |
+ |
#define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_FAULT_INSTRUCTION |
1644 |
+ |
#endif |
1645 |
|
#ifndef SIGSEGV_FAULT_INSTRUCTION |
1646 |
< |
#define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC |
1646 |
> |
#define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_ADDRESS |
1647 |
|
#endif |
1648 |
|
#ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1 |
1649 |
|
#define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST |
1650 |
|
#endif |
1651 |
|
#ifndef SIGSEGV_FAULT_HANDLER_INVOKE |
1652 |
< |
#define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) sigsegv_fault_handler(ADDR, IP) |
1652 |
> |
#define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P) |
1653 |
|
#endif |
1654 |
|
|
1655 |
|
// SIGSEGV recovery supported ? |
1662 |
|
* SIGSEGV global handler |
1663 |
|
*/ |
1664 |
|
|
1665 |
+ |
struct sigsegv_info_t { |
1666 |
+ |
sigsegv_address_t addr; |
1667 |
+ |
sigsegv_address_t pc; |
1668 |
+ |
#ifdef HAVE_MACH_EXCEPTIONS |
1669 |
+ |
mach_port_t thread; |
1670 |
+ |
bool has_exc_state; |
1671 |
+ |
SIGSEGV_EXCEPTION_STATE_TYPE exc_state; |
1672 |
+ |
mach_msg_type_number_t exc_state_count; |
1673 |
+ |
bool has_thr_state; |
1674 |
+ |
SIGSEGV_THREAD_STATE_TYPE thr_state; |
1675 |
+ |
mach_msg_type_number_t thr_state_count; |
1676 |
+ |
#endif |
1677 |
+ |
}; |
1678 |
+ |
|
1679 |
+ |
#ifdef HAVE_MACH_EXCEPTIONS |
1680 |
+ |
static void mach_get_exception_state(sigsegv_info_t *SIP) |
1681 |
+ |
{ |
1682 |
+ |
SIP->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT; |
1683 |
+ |
kern_return_t krc = thread_get_state(SIP->thread, |
1684 |
+ |
SIGSEGV_EXCEPTION_STATE_FLAVOR, |
1685 |
+ |
(natural_t *)&SIP->exc_state, |
1686 |
+ |
&SIP->exc_state_count); |
1687 |
+ |
MACH_CHECK_ERROR(thread_get_state, krc); |
1688 |
+ |
SIP->has_exc_state = true; |
1689 |
+ |
} |
1690 |
+ |
|
1691 |
+ |
static void mach_get_thread_state(sigsegv_info_t *SIP) |
1692 |
+ |
{ |
1693 |
+ |
SIP->thr_state_count = SIGSEGV_THREAD_STATE_COUNT; |
1694 |
+ |
kern_return_t krc = thread_get_state(SIP->thread, |
1695 |
+ |
SIGSEGV_THREAD_STATE_FLAVOR, |
1696 |
+ |
(natural_t *)&SIP->thr_state, |
1697 |
+ |
&SIP->thr_state_count); |
1698 |
+ |
MACH_CHECK_ERROR(thread_get_state, krc); |
1699 |
+ |
SIP->has_thr_state = true; |
1700 |
+ |
} |
1701 |
+ |
|
1702 |
+ |
static void mach_set_thread_state(sigsegv_info_t *SIP) |
1703 |
+ |
{ |
1704 |
+ |
kern_return_t krc = thread_set_state(SIP->thread, |
1705 |
+ |
SIGSEGV_THREAD_STATE_FLAVOR, |
1706 |
+ |
(natural_t *)&SIP->thr_state, |
1707 |
+ |
SIP->thr_state_count); |
1708 |
+ |
MACH_CHECK_ERROR(thread_set_state, krc); |
1709 |
+ |
} |
1710 |
+ |
#endif |
1711 |
+ |
|
1712 |
+ |
// Return the address of the invalid memory reference |
1713 |
+ |
sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *SIP) |
1714 |
+ |
{ |
1715 |
+ |
#ifdef HAVE_MACH_EXCEPTIONS |
1716 |
+ |
static int use_fast_path = -1; |
1717 |
+ |
if (use_fast_path != 1 && !SIP->has_exc_state) { |
1718 |
+ |
mach_get_exception_state(SIP); |
1719 |
+ |
|
1720 |
+ |
sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS; |
1721 |
+ |
if (use_fast_path < 0) |
1722 |
+ |
use_fast_path = addr == SIP->addr; |
1723 |
+ |
SIP->addr = addr; |
1724 |
+ |
} |
1725 |
+ |
#endif |
1726 |
+ |
return SIP->addr; |
1727 |
+ |
} |
1728 |
+ |
|
1729 |
+ |
// Return the address of the instruction that caused the fault, or |
1730 |
+ |
// SIGSEGV_INVALID_ADDRESS if we could not retrieve this information |
1731 |
+ |
sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP) |
1732 |
+ |
{ |
1733 |
+ |
#ifdef HAVE_MACH_EXCEPTIONS |
1734 |
+ |
if (!SIP->has_thr_state) { |
1735 |
+ |
mach_get_thread_state(SIP); |
1736 |
+ |
|
1737 |
+ |
SIP->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION; |
1738 |
+ |
} |
1739 |
+ |
#endif |
1740 |
+ |
return SIP->pc; |
1741 |
+ |
} |
1742 |
+ |
|
1743 |
|
// This function handles the badaccess to memory. |
1744 |
|
// It is called from the signal handler or the exception handler. |
1745 |
|
static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1) |
1746 |
|
{ |
1747 |
+ |
sigsegv_info_t SI; |
1748 |
+ |
SI.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST; |
1749 |
+ |
SI.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST; |
1750 |
|
#ifdef HAVE_MACH_EXCEPTIONS |
1751 |
< |
// We must match the initial count when writing back the CPU state registers |
1752 |
< |
kern_return_t krc; |
1753 |
< |
mach_msg_type_number_t count; |
1621 |
< |
|
1622 |
< |
count = SIGSEGV_THREAD_STATE_COUNT; |
1623 |
< |
krc = thread_get_state(thread, SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state, &count); |
1624 |
< |
MACH_CHECK_ERROR (thread_get_state, krc); |
1751 |
> |
SI.thread = thread; |
1752 |
> |
SI.has_exc_state = false; |
1753 |
> |
SI.has_thr_state = false; |
1754 |
|
#endif |
1755 |
+ |
sigsegv_info_t * const SIP = &SI; |
1756 |
|
|
1627 |
– |
sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS; |
1628 |
– |
sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION; |
1629 |
– |
|
1757 |
|
// Call user's handler and reinstall the global handler, if required |
1758 |
< |
switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) { |
1758 |
> |
switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) { |
1759 |
|
case SIGSEGV_RETURN_SUCCESS: |
1760 |
|
return true; |
1761 |
|
|
1763 |
|
case SIGSEGV_RETURN_SKIP_INSTRUCTION: |
1764 |
|
// Call the instruction skipper with the register file |
1765 |
|
// available |
1766 |
+ |
#ifdef HAVE_MACH_EXCEPTIONS |
1767 |
+ |
if (!SIP->has_thr_state) |
1768 |
+ |
mach_get_thread_state(SIP); |
1769 |
+ |
#endif |
1770 |
|
if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) { |
1771 |
|
#ifdef HAVE_MACH_EXCEPTIONS |
1772 |
|
// Unlike UNIX signals where the thread state |
1773 |
|
// is modified off of the stack, in Mach we |
1774 |
|
// need to actually call thread_set_state to |
1775 |
|
// have the register values updated. |
1776 |
< |
krc = thread_set_state(thread, |
1646 |
< |
SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state, |
1647 |
< |
count); |
1648 |
< |
MACH_CHECK_ERROR (thread_set_state, krc); |
1776 |
> |
mach_set_thread_state(SIP); |
1777 |
|
#endif |
1778 |
|
return true; |
1779 |
|
} |
1782 |
|
case SIGSEGV_RETURN_FAILURE: |
1783 |
|
// We can't do anything with the fault_address, dump state? |
1784 |
|
if (sigsegv_state_dumper != 0) |
1785 |
< |
sigsegv_state_dumper(fault_address, fault_instruction); |
1785 |
> |
sigsegv_state_dumper(SIP); |
1786 |
|
break; |
1787 |
|
} |
1788 |
|
|
1923 |
|
mach_port_t task, |
1924 |
|
exception_type_t exception, |
1925 |
|
exception_data_t code, |
1926 |
< |
mach_msg_type_number_t codeCount) |
1926 |
> |
mach_msg_type_number_t code_count) |
1927 |
|
{ |
1800 |
– |
SIGSEGV_THREAD_STATE_TYPE state; |
1928 |
|
kern_return_t krc; |
1929 |
|
|
1930 |
< |
if ((exception == EXC_BAD_ACCESS) && (codeCount >= 2)) { |
1931 |
< |
if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) |
1932 |
< |
return KERN_SUCCESS; |
1930 |
> |
if (exception == EXC_BAD_ACCESS) { |
1931 |
> |
switch (code[0]) { |
1932 |
> |
case KERN_PROTECTION_FAILURE: |
1933 |
> |
case KERN_INVALID_ADDRESS: |
1934 |
> |
if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) |
1935 |
> |
return KERN_SUCCESS; |
1936 |
> |
break; |
1937 |
> |
} |
1938 |
|
} |
1939 |
|
|
1940 |
|
// In Mach we do not need to remove the exception handler. |
1941 |
|
// If we forward the exception, eventually some exception handler |
1942 |
|
// will take care of this exception. |
1943 |
< |
krc = forward_exception(thread, task, exception, code, codeCount, &ports); |
1943 |
> |
krc = forward_exception(thread, task, exception, code, code_count, &ports); |
1944 |
|
|
1945 |
|
return krc; |
1946 |
|
} |
2264 |
|
static void *b_region, *e_region; |
2265 |
|
#endif |
2266 |
|
|
2267 |
< |
static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address) |
2267 |
> |
static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip) |
2268 |
|
{ |
2269 |
+ |
const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip); |
2270 |
+ |
const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip); |
2271 |
|
#if DEBUG |
2272 |
|
printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address); |
2273 |
|
printf("expected fault at %p\n", page + REF_INDEX); |
2281 |
|
#ifdef __GNUC__ |
2282 |
|
// Make sure reported fault instruction address falls into |
2283 |
|
// expected code range |
2284 |
< |
if (instruction_address != SIGSEGV_INVALID_PC |
2284 |
> |
if (instruction_address != SIGSEGV_INVALID_ADDRESS |
2285 |
|
&& ((instruction_address < (sigsegv_address_t)b_region) || |
2286 |
|
(instruction_address >= (sigsegv_address_t)e_region))) |
2287 |
|
exit(11); |
2292 |
|
} |
2293 |
|
|
2294 |
|
#ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION |
2295 |
< |
static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address) |
2295 |
> |
static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip) |
2296 |
|
{ |
2297 |
+ |
const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip); |
2298 |
+ |
const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip); |
2299 |
|
#if DEBUG |
2300 |
|
printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address); |
2301 |
|
#endif |
2303 |
|
#ifdef __GNUC__ |
2304 |
|
// Make sure reported fault instruction address falls into |
2305 |
|
// expected code range |
2306 |
< |
if (instruction_address != SIGSEGV_INVALID_PC |
2306 |
> |
if (instruction_address != SIGSEGV_INVALID_ADDRESS |
2307 |
|
&& ((instruction_address < (sigsegv_address_t)b_region) || |
2308 |
|
(instruction_address >= (sigsegv_address_t)e_region))) |
2309 |
|
return SIGSEGV_RETURN_FAILURE; |
2389 |
|
|
2390 |
|
if (!sigsegv_install_handler(sigsegv_test_handler)) |
2391 |
|
return 4; |
2392 |
< |
|
2392 |
> |
|
2393 |
|
#ifdef __GNUC__ |
2394 |
|
b_region = &&L_b_region1; |
2395 |
|
e_region = &&L_e_region1; |
2396 |
|
#endif |
2397 |
< |
L_b_region1: |
2398 |
< |
page[REF_INDEX] = REF_VALUE; |
2399 |
< |
if (page[REF_INDEX] != REF_VALUE) |
2400 |
< |
exit(20); |
2401 |
< |
page[REF_INDEX] = REF_VALUE; |
2402 |
< |
BARRIER(); |
2403 |
< |
L_e_region1: |
2397 |
> |
/* This is a really awful hack but otherwise gcc is smart enough |
2398 |
> |
* (or bug'ous enough?) to optimize the labels and place them |
2399 |
> |
* e.g. at the "main" entry point, which is wrong. |
2400 |
> |
*/ |
2401 |
> |
volatile int label_hack = 1; |
2402 |
> |
switch (label_hack) { |
2403 |
> |
case 1: |
2404 |
> |
L_b_region1: |
2405 |
> |
page[REF_INDEX] = REF_VALUE; |
2406 |
> |
if (page[REF_INDEX] != REF_VALUE) |
2407 |
> |
exit(20); |
2408 |
> |
page[REF_INDEX] = REF_VALUE; |
2409 |
> |
BARRIER(); |
2410 |
> |
// fall-through |
2411 |
> |
case 2: |
2412 |
> |
L_e_region1: |
2413 |
> |
BARRIER(); |
2414 |
> |
break; |
2415 |
> |
} |
2416 |
|
|
2417 |
|
if (handler_called != 1) |
2418 |
|
return 5; |
2443 |
|
b_region = &&L_b_region2; |
2444 |
|
e_region = &&L_e_region2; |
2445 |
|
#endif |
2446 |
< |
L_b_region2: |
2447 |
< |
TEST_SKIP_INSTRUCTION(unsigned char); |
2448 |
< |
TEST_SKIP_INSTRUCTION(unsigned short); |
2449 |
< |
TEST_SKIP_INSTRUCTION(unsigned int); |
2450 |
< |
TEST_SKIP_INSTRUCTION(unsigned long); |
2451 |
< |
TEST_SKIP_INSTRUCTION(signed char); |
2452 |
< |
TEST_SKIP_INSTRUCTION(signed short); |
2453 |
< |
TEST_SKIP_INSTRUCTION(signed int); |
2454 |
< |
TEST_SKIP_INSTRUCTION(signed long); |
2455 |
< |
BARRIER(); |
2456 |
< |
L_e_region2: |
2457 |
< |
|
2446 |
> |
switch (label_hack) { |
2447 |
> |
case 1: |
2448 |
> |
L_b_region2: |
2449 |
> |
TEST_SKIP_INSTRUCTION(unsigned char); |
2450 |
> |
TEST_SKIP_INSTRUCTION(unsigned short); |
2451 |
> |
TEST_SKIP_INSTRUCTION(unsigned int); |
2452 |
> |
TEST_SKIP_INSTRUCTION(unsigned long); |
2453 |
> |
TEST_SKIP_INSTRUCTION(signed char); |
2454 |
> |
TEST_SKIP_INSTRUCTION(signed short); |
2455 |
> |
TEST_SKIP_INSTRUCTION(signed int); |
2456 |
> |
TEST_SKIP_INSTRUCTION(signed long); |
2457 |
> |
BARRIER(); |
2458 |
> |
// fall-through |
2459 |
> |
case 2: |
2460 |
> |
L_e_region2: |
2461 |
> |
BARRIER(); |
2462 |
> |
break; |
2463 |
> |
} |
2464 |
|
if (!arch_insn_skipper_tests()) |
2465 |
|
return 20; |
2466 |
|
#endif |