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, |
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 exc_state->dar |
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__ |
617 |
– |
#ifdef i386_SAVED_STATE |
618 |
– |
#define SIGSEGV_THREAD_STATE_TYPE struct i386_saved_state |
619 |
– |
#define SIGSEGV_THREAD_STATE_FLAVOR i386_SAVED_STATE |
620 |
– |
#define SIGSEGV_THREAD_STATE_COUNT i386_SAVED_STATE_COUNT |
621 |
– |
#define SIGSEGV_REGISTER_FILE ((unsigned long *)&state.edi) /* EDI is the first GPR we consider */ |
622 |
– |
#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 exc_state->faultvaddr |
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 */ |
631 |
< |
#endif |
632 |
< |
#define SIGSEGV_FAULT_INSTRUCTION state.eip |
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 |
|
#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 exc_state->faultvaddr |
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_REGISTER_FILE ((unsigned long *)&state.rax) /* RAX is the first GPR we consider */ |
644 |
< |
#define SIGSEGV_FAULT_INSTRUCTION state.rip |
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 |
< |
#ifdef SIGSEGV_EXCEPTION_STATE_TYPE |
653 |
< |
#define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, SIGSEGV_EXCEPTION_STATE_TYPE *exc_state |
649 |
< |
#define SIGSEGV_FAULT_HANDLER_ARGS thread, &exc_state |
650 |
< |
#else |
651 |
< |
#define SIGSEGV_FAULT_ADDRESS code[1] |
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 |
654 |
– |
#endif |
656 |
|
|
657 |
|
// Since there can only be one exception thread running at any time |
658 |
|
// this is not a problem. |
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_ADDRESS |
1647 |
|
#endif |
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) |
1713 |
> |
sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *SIP) |
1714 |
|
{ |
1715 |
< |
return sip->addr; |
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) |
1731 |
> |
sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP) |
1732 |
|
{ |
1733 |
< |
return sip->pc; |
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; |
1684 |
< |
SIGSEGV_THREAD_STATE_TYPE state; |
1685 |
< |
|
1686 |
< |
count = SIGSEGV_THREAD_STATE_COUNT; |
1687 |
< |
krc = thread_get_state(thread, SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)&state, &count); |
1688 |
< |
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 |
|
|
1691 |
– |
sigsegv_info_t si; |
1692 |
– |
si.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS; |
1693 |
– |
si.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION; |
1694 |
– |
|
1757 |
|
// Call user's handler and reinstall the global handler, if required |
1758 |
< |
switch (SIGSEGV_FAULT_HANDLER_INVOKE(&si)) { |
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, |
1711 |
< |
SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)&state, |
1712 |
< |
count); |
1713 |
< |
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(&si); |
1785 |
> |
sigsegv_state_dumper(SIP); |
1786 |
|
break; |
1787 |
|
} |
1788 |
|
|
1931 |
|
switch (code[0]) { |
1932 |
|
case KERN_PROTECTION_FAILURE: |
1933 |
|
case KERN_INVALID_ADDRESS: |
1871 |
– |
{ |
1872 |
– |
#ifdef SIGSEGV_EXCEPTION_STATE_TYPE |
1873 |
– |
SIGSEGV_EXCEPTION_STATE_TYPE exc_state; |
1874 |
– |
mach_msg_type_number_t exc_state_count; |
1875 |
– |
exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT; |
1876 |
– |
krc = thread_get_state(thread, SIGSEGV_EXCEPTION_STATE_FLAVOR, (natural_t *)&exc_state, &exc_state_count); |
1877 |
– |
MACH_CHECK_ERROR (thread_get_state, krc); |
1878 |
– |
#endif |
1879 |
– |
|
1934 |
|
if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) |
1935 |
|
return KERN_SUCCESS; |
1936 |
|
break; |
1937 |
|
} |
1884 |
– |
} |
1938 |
|
} |
1939 |
|
|
1940 |
|
// In Mach we do not need to remove the exception handler. |