Move Source From Main Repo

Based on libunwind-35.4
This commit is contained in:
Thomas A 2023-02-04 19:59:13 -08:00
commit 2708dbea23
65 changed files with 18302 additions and 0 deletions

44
CMakeLists.txt Normal file
View File

@ -0,0 +1,44 @@
project(darling-libsystem_unwind)
cmake_minimum_required(VERSION 3.10)
enable_language(C ASM)
set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 0)
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc -nostdinc++ -fno-rtti -fno-exceptions -funwind-tables -ggdb -O0")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse -msse2 -msse3 -w -nostdinc -fno-rtti -funwind-tables -ggdb -O0")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__DARWIN_UNIX03 -fPIC -w")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -nostdlib -Wl,-flat_namespace -Wl,-undefined,suppress")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
set(libunwind_sources
src/libuwind.cxx
src/Registers.S
src/unw_getcontext.S
src/UnwindLevel1.c
src/UnwindLevel1-gcc-ext.c
src/Unwind-sjlj.c
)
set(DYLIB_INSTALL_NAME "/usr/lib/system/libunwind.dylib")
add_circular(unwind FAT
SOURCES
${libunwind_sources}
SIBLINGS
system_c
keymgr
)
#target_link_libraries(unwind PRIVATE system_c keymgr)
#set_target_properties(unwind PROPERTIES LINKER_LANGUAGE C)
#make_fat(unwind)
include(darling_static_lib)
add_darling_static_library(unwind_static SOURCES ${libunwind_sources})
set_target_properties(unwind_static PROPERTIES COMPILE_FLAGS "-DNDEBUG=1")
make_fat(unwind_static)
install(TARGETS unwind DESTINATION libexec/darling/usr/lib/system)

302
include/libunwind.h Normal file
View File

@ -0,0 +1,302 @@
/* -*- mode: C; c-basic-offset: 4; -*-
*
* Copyright (c) 2008-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*
* C interface to libuwind
*
* Source compatible with libuwind API documented at:
* http://www.nongnu.org/libunwind/man/libunwind(3).html
*
*/
#ifndef __LIBUNWIND__
#define __LIBUNWIND__
#include <stdint.h>
#include <stddef.h>
#include <mach/mach_types.h>
#include <Availability.h>
/* error codes */
enum {
UNW_ESUCCESS = 0, /* no error */
UNW_EUNSPEC = -6540, /* unspecified (general) error */
UNW_ENOMEM = -6541, /* out of memory */
UNW_EBADREG = -6542, /* bad register number */
UNW_EREADONLYREG = -6543, /* attempt to write read-only register */
UNW_ESTOPUNWIND = -6544, /* stop unwinding */
UNW_EINVALIDIP = -6545, /* invalid IP */
UNW_EBADFRAME = -6546, /* bad frame */
UNW_EINVAL = -6547, /* unsupported operation or bad value */
UNW_EBADVERSION = -6548, /* unwind info has unsupported version */
UNW_ENOINFO = -6549 /* no unwind info found */
};
struct unw_context_t { uint64_t data[128]; };
typedef struct unw_context_t unw_context_t;
struct unw_cursor_t { uint64_t data[140]; };
typedef struct unw_cursor_t unw_cursor_t;
typedef struct unw_addr_space* unw_addr_space_t;
typedef int unw_regnum_t;
typedef uint64_t unw_word_t;
typedef double unw_fpreg_t;
struct unw_proc_info_t
{
unw_word_t start_ip; /* start address of function */
unw_word_t end_ip; /* address after end of function */
unw_word_t lsda; /* address of language specific data area, or zero if not used */
unw_word_t handler; /* personality routine, or zero if not used */
unw_word_t gp; /* not used */
unw_word_t flags; /* not used */
uint32_t format; /* compact unwind encoding, or zero if none */
uint32_t unwind_info_size; /* size of dwarf unwind info, or zero if none */
unw_word_t unwind_info; /* address of dwarf unwind info, or zero if none */
unw_word_t extra; /* mach_header of mach-o image containing function */
};
typedef struct unw_proc_info_t unw_proc_info_t;
#ifdef __cplusplus
extern "C" {
#endif
#if !__arm__
extern int unw_getcontext(unw_context_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern int unw_init_local(unw_cursor_t*, unw_context_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern int unw_step(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern int unw_get_reg(unw_cursor_t*, unw_regnum_t, unw_word_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern int unw_get_fpreg(unw_cursor_t*, unw_regnum_t, unw_fpreg_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern int unw_set_reg(unw_cursor_t*, unw_regnum_t, unw_word_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern int unw_set_fpreg(unw_cursor_t*, unw_regnum_t, unw_fpreg_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern int unw_resume(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern const char* unw_regname(unw_cursor_t*, unw_regnum_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern int unw_get_proc_info(unw_cursor_t*, unw_proc_info_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern int unw_is_fpreg(unw_cursor_t*, unw_regnum_t) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern int unw_is_signal_frame(unw_cursor_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
extern int unw_get_proc_name(unw_cursor_t*, char*, size_t, unw_word_t*) __OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_5_0);
//extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*);
#endif
#if UNW_REMOTE
/*
* Mac OS X "remote" API for unwinding other processes on same machine
*
*/
extern unw_addr_space_t unw_local_addr_space;
extern unw_addr_space_t unw_create_addr_space_for_task(task_t);
extern void unw_destroy_addr_space(unw_addr_space_t);
extern int unw_init_remote_thread(unw_cursor_t*, unw_addr_space_t, thread_t*);
#endif
/*
* traditional libuwind "remote" API
* NOT IMPLEMENTED on Mac OS X
*
* extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t, thread_t*);
* extern unw_accessors_t unw_get_accessors(unw_addr_space_t);
* extern unw_addr_space_t unw_create_addr_space(unw_accessors_t, int);
* extern void unw_flush_cache(unw_addr_space_t, unw_word_t, unw_word_t);
* extern int unw_set_caching_policy(unw_addr_space_t, unw_caching_policy_t);
* extern void _U_dyn_register(unw_dyn_info_t*);
* extern void _U_dyn_cancel(unw_dyn_info_t*);
*/
#ifdef __cplusplus
}
#endif
// architecture independent register numbers
enum {
UNW_REG_IP = -1, // instruction pointer
UNW_REG_SP = -2, // stack pointer
};
// 32-bit x86 registers
enum {
UNW_X86_EAX = 0,
UNW_X86_ECX = 1,
UNW_X86_EDX = 2,
UNW_X86_EBX = 3,
UNW_X86_EBP = 4,
UNW_X86_ESP = 5,
UNW_X86_ESI = 6,
UNW_X86_EDI = 7
};
// 64-bit x86_64 registers
enum {
UNW_X86_64_RAX = 0,
UNW_X86_64_RDX = 1,
UNW_X86_64_RCX = 2,
UNW_X86_64_RBX = 3,
UNW_X86_64_RSI = 4,
UNW_X86_64_RDI = 5,
UNW_X86_64_RBP = 6,
UNW_X86_64_RSP = 7,
UNW_X86_64_R8 = 8,
UNW_X86_64_R9 = 9,
UNW_X86_64_R10 = 10,
UNW_X86_64_R11 = 11,
UNW_X86_64_R12 = 12,
UNW_X86_64_R13 = 13,
UNW_X86_64_R14 = 14,
UNW_X86_64_R15 = 15
};
// 32-bit ppc register numbers
enum {
UNW_PPC_R0 = 0,
UNW_PPC_R1 = 1,
UNW_PPC_R2 = 2,
UNW_PPC_R3 = 3,
UNW_PPC_R4 = 4,
UNW_PPC_R5 = 5,
UNW_PPC_R6 = 6,
UNW_PPC_R7 = 7,
UNW_PPC_R8 = 8,
UNW_PPC_R9 = 9,
UNW_PPC_R10 = 10,
UNW_PPC_R11 = 11,
UNW_PPC_R12 = 12,
UNW_PPC_R13 = 13,
UNW_PPC_R14 = 14,
UNW_PPC_R15 = 15,
UNW_PPC_R16 = 16,
UNW_PPC_R17 = 17,
UNW_PPC_R18 = 18,
UNW_PPC_R19 = 19,
UNW_PPC_R20 = 20,
UNW_PPC_R21 = 21,
UNW_PPC_R22 = 22,
UNW_PPC_R23 = 23,
UNW_PPC_R24 = 24,
UNW_PPC_R25 = 25,
UNW_PPC_R26 = 26,
UNW_PPC_R27 = 27,
UNW_PPC_R28 = 28,
UNW_PPC_R29 = 29,
UNW_PPC_R30 = 30,
UNW_PPC_R31 = 31,
UNW_PPC_F0 = 32,
UNW_PPC_F1 = 33,
UNW_PPC_F2 = 34,
UNW_PPC_F3 = 35,
UNW_PPC_F4 = 36,
UNW_PPC_F5 = 37,
UNW_PPC_F6 = 38,
UNW_PPC_F7 = 39,
UNW_PPC_F8 = 40,
UNW_PPC_F9 = 41,
UNW_PPC_F10 = 42,
UNW_PPC_F11 = 43,
UNW_PPC_F12 = 44,
UNW_PPC_F13 = 45,
UNW_PPC_F14 = 46,
UNW_PPC_F15 = 47,
UNW_PPC_F16 = 48,
UNW_PPC_F17 = 49,
UNW_PPC_F18 = 50,
UNW_PPC_F19 = 51,
UNW_PPC_F20 = 52,
UNW_PPC_F21 = 53,
UNW_PPC_F22 = 54,
UNW_PPC_F23 = 55,
UNW_PPC_F24 = 56,
UNW_PPC_F25 = 57,
UNW_PPC_F26 = 58,
UNW_PPC_F27 = 59,
UNW_PPC_F28 = 60,
UNW_PPC_F29 = 61,
UNW_PPC_F30 = 62,
UNW_PPC_F31 = 63,
UNW_PPC_MQ = 64,
UNW_PPC_LR = 65,
UNW_PPC_CTR = 66,
UNW_PPC_AP = 67,
UNW_PPC_CR0 = 68,
UNW_PPC_CR1 = 69,
UNW_PPC_CR2 = 70,
UNW_PPC_CR3 = 71,
UNW_PPC_CR4 = 72,
UNW_PPC_CR5 = 73,
UNW_PPC_CR6 = 74,
UNW_PPC_CR7 = 75,
UNW_PPC_XER = 76,
UNW_PPC_V0 = 77,
UNW_PPC_V1 = 78,
UNW_PPC_V2 = 79,
UNW_PPC_V3 = 80,
UNW_PPC_V4 = 81,
UNW_PPC_V5 = 82,
UNW_PPC_V6 = 83,
UNW_PPC_V7 = 84,
UNW_PPC_V8 = 85,
UNW_PPC_V9 = 86,
UNW_PPC_V10 = 87,
UNW_PPC_V11 = 88,
UNW_PPC_V12 = 89,
UNW_PPC_V13 = 90,
UNW_PPC_V14 = 91,
UNW_PPC_V15 = 92,
UNW_PPC_V16 = 93,
UNW_PPC_V17 = 94,
UNW_PPC_V18 = 95,
UNW_PPC_V19 = 96,
UNW_PPC_V20 = 97,
UNW_PPC_V21 = 98,
UNW_PPC_V22 = 99,
UNW_PPC_V23 = 100,
UNW_PPC_V24 = 101,
UNW_PPC_V25 = 102,
UNW_PPC_V26 = 103,
UNW_PPC_V27 = 104,
UNW_PPC_V28 = 105,
UNW_PPC_V29 = 106,
UNW_PPC_V30 = 107,
UNW_PPC_V31 = 108,
UNW_PPC_VRSAVE = 109,
UNW_PPC_VSCR = 110,
UNW_PPC_SPE_ACC = 111,
UNW_PPC_SPEFSCR = 112
};
#endif

View File

@ -0,0 +1,428 @@
/* -*- mode: C; c-basic-offset: 4; tab-width: 4 -*-
*
* Copyright (c) 2008-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef __COMPACT_UNWIND_ENCODING__
#define __COMPACT_UNWIND_ENCODING__
#include <stdint.h>
//
// Compilers can emit standard Dwarf FDEs in the __TEXT,__eh_frame section
// of object files. Or compilers can emit compact unwind information in
// the __LD,__compact_unwind section.
//
// When the linker creates a final linked image, it will create a
// __TEXT,__unwind_info section. This section is a small and fast way for the
// runtime to access unwind info for any given function. If the compiler emitted
// compact unwind info for the function, that compact unwind info will be encoded
// in the __TEXT,__unwind_info section. If the compiler emitted dwarf unwind info,
// the __TEXT,__unwind_info section will contain the offset of the FDE in the
// __TEXT,__eh_frame section in the final linked image.
//
// Note: Previously, the linker would transform some dwarf unwind infos into
// compact unwind info. But that is fragile and no longer done.
//
// The compact unwind endoding is a 32-bit value which encoded in an architecture
// specific way, which registers to restore from where, and how to unwind out
// of the function.
//
typedef uint32_t compact_unwind_encoding_t;
// architecture independent bits
enum {
UNWIND_IS_NOT_FUNCTION_START = 0x80000000,
UNWIND_HAS_LSDA = 0x40000000,
UNWIND_PERSONALITY_MASK = 0x30000000,
};
//
// x86
//
// 1-bit: start
// 1-bit: has lsda
// 2-bit: personality index
//
// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=dwarf
// ebp based:
// 15-bits (5*3-bits per reg) register permutation
// 8-bits for stack offset
// frameless:
// 8-bits stack size
// 3-bits stack adjust
// 3-bits register count
// 10-bits register permutation
//
enum {
UNWIND_X86_MODE_MASK = 0x0F000000,
UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
UNWIND_X86_MODE_STACK_IND = 0x03000000,
UNWIND_X86_MODE_DWARF = 0x04000000,
UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
};
enum {
UNWIND_X86_REG_NONE = 0,
UNWIND_X86_REG_EBX = 1,
UNWIND_X86_REG_ECX = 2,
UNWIND_X86_REG_EDX = 3,
UNWIND_X86_REG_EDI = 4,
UNWIND_X86_REG_ESI = 5,
UNWIND_X86_REG_EBP = 6,
};
//
// For x86 there are four modes for the compact unwind encoding:
// UNWIND_X86_MODE_EBP_FRAME:
// EBP based frame where EBP is push on stack immediately after return address,
// then ESP is moved to EBP. Thus, to unwind ESP is restored with the current
// EPB value, then EBP is restored by popping off the stack, and the return
// is done by popping the stack once more into the pc.
// All non-volatile registers that need to be restored must have been saved
// in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4
// is encoded in the UNWIND_X86_EBP_FRAME_OFFSET bits. The registers saved
// are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries.
// Each entry contains which register to restore.
// UNWIND_X86_MODE_STACK_IMMD:
// A "frameless" (EBP not used as frame pointer) function with a small
// constant stack size. To return, a constant (encoded in the compact
// unwind encoding) is added to the ESP. Then the return is done by
// popping the stack into the pc.
// All non-volatile registers that need to be restored must have been saved
// on the stack immediately after the return address. The stack_size/4 is
// encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024).
// The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT.
// UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
// saved and their order.
// UNWIND_X86_MODE_STACK_IND:
// A "frameless" (EBP not used as frame pointer) function large constant
// stack size. This case is like the previous, except the stack size is too
// large to encode in the compact unwind encoding. Instead it requires that
// the function contains "subl $nnnnnnnn,ESP" in its prolog. The compact
// encoding contains the offset to the nnnnnnnn value in the function in
// UNWIND_X86_FRAMELESS_STACK_SIZE.
// UNWIND_X86_MODE_DWARF:
// No compact unwind encoding is available. Instead the low 24-bits of the
// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
// This mode is never used in object files. It is only generated by the
// linker in final linked images which have only dwarf unwind info for a
// function.
//
// The following is the algorithm used to create the permutation encoding used
// with frameless stacks. It is passed the number of registers to be saved and
// an array of the register numbers saved.
//
//uint32_t permute_encode(uint32_t registerCount, const uint32_t registers[6])
//{
// uint32_t renumregs[6];
// for (int i=6-registerCount; i < 6; ++i) {
// int countless = 0;
// for (int j=6-registerCount; j < i; ++j) {
// if ( registers[j] < registers[i] )
// ++countless;
// }
// renumregs[i] = registers[i] - countless -1;
// }
// uint32_t permutationEncoding = 0;
// switch ( registerCount ) {
// case 6:
// permutationEncoding |= (120*renumregs[0] + 24*renumregs[1]
// + 6*renumregs[2] + 2*renumregs[3]
// + renumregs[4]);
// break;
// case 5:
// permutationEncoding |= (120*renumregs[1] + 24*renumregs[2]
// + 6*renumregs[3] + 2*renumregs[4]
// + renumregs[5]);
// break;
// case 4:
// permutationEncoding |= (60*renumregs[2] + 12*renumregs[3]
// + 3*renumregs[4] + renumregs[5]);
// break;
// case 3:
// permutationEncoding |= (20*renumregs[3] + 4*renumregs[4]
// + renumregs[5]);
// break;
// case 2:
// permutationEncoding |= (5*renumregs[4] + renumregs[5]);
// break;
// case 1:
// permutationEncoding |= (renumregs[5]);
// break;
// }
// return permutationEncoding;
//}
//
//
// x86_64
//
// 1-bit: start
// 1-bit: has lsda
// 2-bit: personality index
//
// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=dwarf
// rbp based:
// 15-bits (5*3-bits per reg) register permutation
// 8-bits for stack offset
// frameless:
// 8-bits stack size
// 3-bits stack adjust
// 3-bits register count
// 10-bits register permutation
//
enum {
UNWIND_X86_64_MODE_MASK = 0x0F000000,
UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
UNWIND_X86_64_MODE_DWARF = 0x04000000,
UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
};
enum {
UNWIND_X86_64_REG_NONE = 0,
UNWIND_X86_64_REG_RBX = 1,
UNWIND_X86_64_REG_R12 = 2,
UNWIND_X86_64_REG_R13 = 3,
UNWIND_X86_64_REG_R14 = 4,
UNWIND_X86_64_REG_R15 = 5,
UNWIND_X86_64_REG_RBP = 6,
};
//
// For x86_64 there are four modes for the compact unwind encoding:
// UNWIND_X86_64_MODE_RBP_FRAME:
// RBP based frame where RBP is push on stack immediately after return address,
// then RSP is moved to RBP. Thus, to unwind RSP is restored with the current
// EPB value, then RBP is restored by popping off the stack, and the return
// is done by popping the stack once more into the pc.
// All non-volatile registers that need to be restored must have been saved
// in a small range in the stack that starts RBP-8 to RBP-1020. The offset/4
// is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits. The registers saved
// are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries.
// Each entry contains which register to restore.
// UNWIND_X86_64_MODE_STACK_IMMD:
// A "frameless" (RBP not used as frame pointer) function with a small
// constant stack size. To return, a constant (encoded in the compact
// unwind encoding) is added to the RSP. Then the return is done by
// popping the stack into the pc.
// All non-volatile registers that need to be restored must have been saved
// on the stack immediately after the return address. The stack_size/4 is
// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 1024).
// The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT.
// UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
// saved and their order.
// UNWIND_X86_64_MODE_STACK_IND:
// A "frameless" (RBP not used as frame pointer) function large constant
// stack size. This case is like the previous, except the stack size is too
// large to encode in the compact unwind encoding. Instead it requires that
// the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact
// encoding contains the offset to the nnnnnnnn value in the function in
// UNWIND_X86_64_FRAMELESS_STACK_SIZE.
// UNWIND_X86_64_MODE_DWARF:
// No compact unwind encoding is available. Instead the low 24-bits of the
// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
// This mode is never used in object files. It is only generated by the
// linker in final linked images which have only dwarf unwind info for a
// function.
//
////////////////////////////////////////////////////////////////////////////////
//
// Relocatable Object Files: __LD,__compact_unwind
//
////////////////////////////////////////////////////////////////////////////////
//
// A compiler can generated compact unwind information for a function by adding
// a "row" to the __LD,__compact_unwind section. This section has the
// S_ATTR_DEBUG bit set, so the section will be ignored by older linkers.
// It is removed by the new linker, so never ends up in final executables.
// This section is a table, initially with one row per function (that needs
// unwind info). The table columns and some conceptual entries are:
//
// range-start pointer to start of function/range
// range-length
// compact-unwind-encoding 32-bit encoding
// personality-function or zero if no personality function
// lsda or zero if no LSDA data
//
// The length and encoding fields are 32-bits. The other are all pointer sized.
//
// In x86_64 assembly, these entry would look like:
//
// .section __LD,__compact_unwind,regular,debug
//
// #compact unwind for _foo
// .quad _foo
// .set L1,LfooEnd-_foo
// .long L1
// .long 0x01010001
// .quad 0
// .quad 0
//
// #compact unwind for _bar
// .quad _bar
// .set L2,LbarEnd-_bar
// .long L2
// .long 0x01020011
// .quad __gxx_personality
// .quad except_tab1
//
//
// Notes: There is no need for any labels in the the __compact_unwind section.
// The use of the .set directive is to force the evaluation of the
// range-length at assembly time, instead of generating relocations.
//
// To support future compiler optimizations where which non-volatile registers
// are saved changes within a function (e.g. delay saving non-volatiles until
// necessary), there can by multiple lines in the __compact_unwind table for one
// function, each with a different (non-overlapping) range and each with
// different compact unwind encodings that correspond to the non-volatiles
// saved at that range of the function.
//
// If a particular function is so wacky that there is no compact unwind way
// to encode it, then the compiler can emit traditional dwarf unwind info.
// The runtime will use which ever is available.
//
// Runtime support for compact unwind encodings are only available on 10.6
// and later. So, the compiler should not generate it when targeting pre-10.6.
////////////////////////////////////////////////////////////////////////////////
//
// Final Linked Images: __TEXT,__unwind_info
//
////////////////////////////////////////////////////////////////////////////////
//
// The __TEXT,__unwind_info section is laid out for an efficient two level lookup.
// The header of the section contains a coarse index that maps function address
// to the page (4096 byte block) containing the unwind info for that function.
//
#define UNWIND_SECTION_VERSION 1
struct unwind_info_section_header
{
uint32_t version; // UNWIND_SECTION_VERSION
uint32_t commonEncodingsArraySectionOffset;
uint32_t commonEncodingsArrayCount;
uint32_t personalityArraySectionOffset;
uint32_t personalityArrayCount;
uint32_t indexSectionOffset;
uint32_t indexCount;
// compact_unwind_encoding_t[]
// uintptr_t personalities[]
// unwind_info_section_header_index_entry[]
// unwind_info_section_header_lsda_index_entry[]
};
struct unwind_info_section_header_index_entry
{
uint32_t functionOffset;
uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page
uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range
};
struct unwind_info_section_header_lsda_index_entry
{
uint32_t functionOffset;
uint32_t lsdaOffset;
};
//
// There are two kinds of second level index pages: regular and compressed.
// A compressed page can hold up to 1021 entries, but it cannot be used
// if too many different encoding types are used. The regular page holds
// 511 entries.
//
struct unwind_info_regular_second_level_entry
{
uint32_t functionOffset;
compact_unwind_encoding_t encoding;
};
#define UNWIND_SECOND_LEVEL_REGULAR 2
struct unwind_info_regular_second_level_page_header
{
uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
uint16_t entryPageOffset;
uint16_t entryCount;
// entry array
};
#define UNWIND_SECOND_LEVEL_COMPRESSED 3
struct unwind_info_compressed_second_level_page_header
{
uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED
uint16_t entryPageOffset;
uint16_t entryCount;
uint16_t encodingsPageOffset;
uint16_t encodingsCount;
// 32-bit entry array
// encodings array
};
#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF)
#endif

232
include/unwind.h Normal file
View File

@ -0,0 +1,232 @@
/* -*- mode: C++; c-basic-offset: 4; -*-
*
* Copyright (c) 2010-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*
* C interface to libuwind
*
* Source compatible with Level 1 Base ABI documented at:
* http://www.codesourcery.com/public/cxx-abi/abi-eh.html
*
*/
#ifndef __UNWIND_H__
#define __UNWIND_H__
#include <stdint.h>
#include <stddef.h>
#include <Availability.h>
typedef enum {
_URC_NO_REASON = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
_URC_FATAL_PHASE2_ERROR = 2,
_URC_FATAL_PHASE1_ERROR = 3,
_URC_NORMAL_STOP = 4,
_URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8
} _Unwind_Reason_Code;
typedef enum {
_UA_SEARCH_PHASE = 1,
_UA_CLEANUP_PHASE = 2,
_UA_HANDLER_FRAME = 4,
_UA_FORCE_UNWIND = 8,
_UA_END_OF_STACK = 16 // gcc extension to C++ ABI
} _Unwind_Action;
struct _Unwind_Context; // opaque
struct _Unwind_Exception; // forward declaration
struct _Unwind_Exception {
uint64_t exception_class;
void (*exception_cleanup)(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc);
uintptr_t private_1; // non-zero means forced unwind
uintptr_t private_2; // holds sp that phase1 found for phase2 to use
#if !__LP64__
// The gcc implementation of _Unwind_Exception used attribute mode on the above fields
// which had the side effect of causing this whole struct to round up to 32 bytes in size.
// To be more explicit, we add pad fields added for binary compatibility.
uint32_t reserved[3];
#endif
};
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
(int version,
_Unwind_Action actions,
uint64_t exceptionClass,
struct _Unwind_Exception* exceptionObject,
struct _Unwind_Context* context,
void* stop_parameter );
typedef _Unwind_Reason_Code (*__personality_routine)
(int version,
_Unwind_Action actions,
uint64_t exceptionClass,
struct _Unwind_Exception* exceptionObject,
struct _Unwind_Context* context);
#ifdef __cplusplus
extern "C" {
#endif
//
// The following are the base functions documented by the C++ ABI
//
#if __arm__
extern _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception* exception_object);
extern void _Unwind_SjLj_Resume(struct _Unwind_Exception* exception_object);
#else
extern _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception* exception_object);
extern void _Unwind_Resume(struct _Unwind_Exception* exception_object);
#endif
extern void _Unwind_DeleteException(struct _Unwind_Exception* exception_object);
extern uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index);
extern void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value);
extern uintptr_t _Unwind_GetIP(struct _Unwind_Context* context);
extern void _Unwind_SetIP(struct _Unwind_Context*, uintptr_t new_value);
extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context);
extern uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context);
#if __arm__
extern _Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter );
#else
extern _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter );
#endif
#if __arm__
typedef struct _Unwind_FunctionContext* _Unwind_FunctionContext_t;
extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc);
extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc);
#endif
//
// The following are semi-suppoted extensions to the C++ ABI
//
//
// called by __cxa_rethrow().
//
#if __arm__
extern _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception* exception_object);
#else
extern _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception* exception_object);
#endif
//
// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the
// _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack
// or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON.
//
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context*, void*);
extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*);
//
// _Unwind_GetCFA is a gcc extension that can be called from within a personality
// handler to get the CFA (stack pointer before call) of current frame.
//
extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context*);
//
// _Unwind_GetIPInfo is a gcc extension that can be called from within a personality
// handler. Similar to _Unwind_GetIP() but also returns in *ipBefore a non-zero
// value if the instruction pointer is at or before the instruction causing
// the unwind. Normally, in a function call, the IP returned is the return address
// which is after the call instruction and may be past the end of the function
// containing the call instruction.
//
extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore);
//
// __register_frame() is used with dynamically generated code to register the FDE
// for a generated (JIT) code. The FDE must use pc-rel addressing to point to its
// function and optional LSDA. __register_frame() has existed in all versions of
// Mac OS X, but in 10.4 and 10.5 it was buggy and did not actually register the
// FDE with the unwinder. In 10.6 and later it does register properly.
//
extern void __register_frame(const void* fde);
extern void __deregister_frame(const void* fde);
//
// _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has
// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind info"
// which the runtime uses in preference to dwarf unwind info. This function
// will only work if the target function has an FDE but no compact unwind info.
//
struct dwarf_eh_bases
{
uintptr_t tbase;
uintptr_t dbase;
uintptr_t func;
};
extern const void* _Unwind_Find_FDE(const void* pc, struct dwarf_eh_bases*);
//
// This function attempts to find the start (address of first instruction) of
// a function given an address inside the function. It only works if the function
// has an FDE (dwarf unwind info).
// This function is unimplemented on Mac OS X 10.6 and later. Instead, use
// _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result.
extern void* _Unwind_FindEnclosingFunction(void* pc);
// Mac OS X does not support text-rel and data-rel addressing so these functions are unimplemented
extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context) __attribute__((unavailable));
extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context) __attribute__((unavailable));
// Mac OS X 10.4 and 10.5 had implementations of these functions in libgcc_s.dylib,
// but they never worked. These functions are no longer available.
extern void __register_frame_info_bases(const void* fde, void* ob, void* tb, void* db) __attribute__((unavailable));
extern void __register_frame_info(const void* fde, void* ob) __attribute__((unavailable));
extern void __register_frame_info_table_bases(const void* fde, void* ob,void* tb, void* db) __attribute__((unavailable));
extern void __register_frame_info_table(const void* fde, void* ob) __attribute__((unavailable));
extern void __register_frame_table(const void* fde) __attribute__((unavailable));
extern void* __deregister_frame_info(const void* fde) __attribute__((unavailable));
extern void* __deregister_frame_info_bases(const void* fde) __attribute__((unavailable));
#ifdef __cplusplus
}
#endif
#endif // __UNWIND_H__

27
libunwind.order Normal file
View File

@ -0,0 +1,27 @@
__Unwind_RaiseException
_unw_getcontext
_unw_init_local
x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE24setInfoBasedOnIPRegisterEb
x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE6getRegEi
x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE33getInfoFromCompactEncodingSectionEyyy
_unw_step
x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE4stepEv
x86_64:__ZN9libunwind22CompactUnwinder_x86_64INS_17LocalAddressSpaceEE23stepWithCompactEncodingEjyRS1_RNS_16Registers_x86_64E
x86_64:__ZN9libunwind22CompactUnwinder_x86_64INS_17LocalAddressSpaceEE31stepWithCompactEncodingRBPFrameEjyRS1_RNS_16Registers_x86_64E
_unw_get_proc_info
x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE7getInfoEP15unw_proc_info_t
__Unwind_GetLanguageSpecificData
__Unwind_GetRegionStart
__Unwind_GetIP
_unw_get_reg
x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE8validRegEi
_unwind_phase2
__Unwind_SetGR
_unw_set_reg
x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE6setRegEiy
__Unwind_SetIP
_unw_resume
x86_64:__ZN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_16Registers_x86_64EE6jumptoEv
x86_64:__ZN9libunwind16Registers_x86_646jumptoEv
__Unwind_DeleteException

View File

@ -0,0 +1,546 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 45;
objects = {
/* Begin PBXAggregateTarget section */
F93A98ED0EC91269000D227E /* all */ = {
isa = PBXAggregateTarget;
buildConfigurationList = F93A98F70EC91298000D227E /* Build configuration list for PBXAggregateTarget "all" */;
buildPhases = (
F97377A8133A82A600BDE64E /* Simulator clean up */,
);
dependencies = (
F992F1FB11A35E2F0008F9B0 /* PBXTargetDependency */,
F93A98F50EC9127A000D227E /* PBXTargetDependency */,
);
name = all;
productName = macosx;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
F9276EFD0E6E0B6100B731C9 /* libuwind.cxx in Sources */ = {isa = PBXBuildFile; fileRef = F98BEABC0D121A4000F298D0 /* libuwind.cxx */; };
F9276EFE0E6E0B6100B731C9 /* UnwindLevel1.c in Sources */ = {isa = PBXBuildFile; fileRef = F92C4CC60DC0145500EE1253 /* UnwindLevel1.c */; };
F9276F000E6E0B6100B731C9 /* Registers.s in Sources */ = {isa = PBXBuildFile; fileRef = F98BEA710D10CC1700F298D0 /* Registers.s */; };
F9276F010E6E0B6100B731C9 /* unw_getcontext.s in Sources */ = {isa = PBXBuildFile; fileRef = F98BEA4B0D10C13500F298D0 /* unw_getcontext.s */; };
F9276F280E6E0D1400B731C9 /* UnwindLevel1-gcc-ext.c in Sources */ = {isa = PBXBuildFile; fileRef = F903E4D70DC16974007E8D28 /* UnwindLevel1-gcc-ext.c */; };
F92A25C413C69AEE008F010E /* libunwind.h in install usr-include */ = {isa = PBXBuildFile; fileRef = F98BE9080D0F3D7D00F298D0 /* libunwind.h */; };
F92A25C513C69AEE008F010E /* unwind.h in install usr-include */ = {isa = PBXBuildFile; fileRef = F9ABAAA91118B2BB00A06182 /* unwind.h */; };
F92A25C913C69B39008F010E /* compact_unwind_encoding.h in install usr-include-mach-o */ = {isa = PBXBuildFile; fileRef = F9BFF9C60DC935360077A618 /* compact_unwind_encoding.h */; };
F938B7C70F97F50D0096ACC8 /* Unwind-sjlj.c in Sources */ = {isa = PBXBuildFile; fileRef = F938B7C50F97F50D0096ACC8 /* Unwind-sjlj.c */; };
F95A3D8B0DE3A8AA004B72E5 /* libuwind.cxx in Sources */ = {isa = PBXBuildFile; fileRef = F98BEABC0D121A4000F298D0 /* libuwind.cxx */; settings = {COMPILER_FLAGS = "-fno-exceptions"; }; };
F95A3D8C0DE3A8AA004B72E5 /* Registers.s in Sources */ = {isa = PBXBuildFile; fileRef = F98BEA710D10CC1700F298D0 /* Registers.s */; };
F95A3D8D0DE3A8AA004B72E5 /* unw_getcontext.s in Sources */ = {isa = PBXBuildFile; fileRef = F98BEA4B0D10C13500F298D0 /* unw_getcontext.s */; };
F95A3D8E0DE3A8AA004B72E5 /* UnwindLevel1.c in Sources */ = {isa = PBXBuildFile; fileRef = F92C4CC60DC0145500EE1253 /* UnwindLevel1.c */; };
F95A3D8F0DE3A8AA004B72E5 /* UnwindLevel1-gcc-ext.c in Sources */ = {isa = PBXBuildFile; fileRef = F903E4D70DC16974007E8D28 /* UnwindLevel1-gcc-ext.c */; };
F98F98F311A47E2C00D21E1F /* Unwind-sjlj.c in Sources */ = {isa = PBXBuildFile; fileRef = F938B7C50F97F50D0096ACC8 /* Unwind-sjlj.c */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
F93A98F40EC9127A000D227E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = F9276EFA0E6E0B6100B731C9;
remoteInfo = "dyld-libunwind";
};
F992F1FA11A35E2F0008F9B0 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = F95A3D890DE3A8AA004B72E5;
remoteInfo = "libunwind-system";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
F92A25CA13C69B62008F010E /* install usr-include */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
dstPath = "$(INSTALL_PATH_PREFIX)/usr/include";
dstSubfolderSpec = 0;
files = (
F92A25C413C69AEE008F010E /* libunwind.h in install usr-include */,
F92A25C513C69AEE008F010E /* unwind.h in install usr-include */,
);
name = "install usr-include";
runOnlyForDeploymentPostprocessing = 1;
};
F92A25CB13C69B62008F010E /* install usr-include-mach-o */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
dstPath = "$(INSTALL_PATH_PREFIX)/usr/include/mach-o";
dstSubfolderSpec = 0;
files = (
F92A25C913C69B39008F010E /* compact_unwind_encoding.h in install usr-include-mach-o */,
);
name = "install usr-include-mach-o";
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
F903E4D70DC16974007E8D28 /* UnwindLevel1-gcc-ext.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "UnwindLevel1-gcc-ext.c"; path = "src/UnwindLevel1-gcc-ext.c"; sourceTree = "<group>"; };
F9276F140E6E0B6100B731C9 /* libunwind.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libunwind.a; sourceTree = BUILT_PRODUCTS_DIR; };
F92C4CC60DC0145500EE1253 /* UnwindLevel1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = UnwindLevel1.c; path = src/UnwindLevel1.c; sourceTree = "<group>"; };
F938B7C50F97F50D0096ACC8 /* Unwind-sjlj.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "Unwind-sjlj.c"; path = "src/Unwind-sjlj.c"; sourceTree = "<group>"; };
F94138D00D1C7AC600B5EA0C /* dwarf2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2.h; path = src/dwarf2.h; sourceTree = "<group>"; };
F94139850D25A12200B5EA0C /* UnwindCursor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = UnwindCursor.hpp; path = src/UnwindCursor.hpp; sourceTree = "<group>"; };
F9413A530D25D7E100B5EA0C /* AddressSpace.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = AddressSpace.hpp; path = src/AddressSpace.hpp; sourceTree = "<group>"; };
F9413A540D25D7E100B5EA0C /* Registers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Registers.hpp; path = src/Registers.hpp; sourceTree = "<group>"; };
F95A3D950DE3A8AA004B72E5 /* libunwind.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libunwind.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
F95BE2990D2EB9EA007E3672 /* DwarfInstructions.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = DwarfInstructions.hpp; path = src/DwarfInstructions.hpp; sourceTree = "<group>"; };
F95BE31A0D2EED80007E3672 /* CompactUnwinder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CompactUnwinder.hpp; path = src/CompactUnwinder.hpp; sourceTree = "<group>"; };
F95BE4DC0D343AB9007E3672 /* DwarfParser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = DwarfParser.hpp; path = src/DwarfParser.hpp; sourceTree = "<group>"; };
F95DF59A0DEDD12800B8DA7A /* InternalMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InternalMacros.h; path = src/InternalMacros.h; sourceTree = "<group>"; };
F98BE9080D0F3D7D00F298D0 /* libunwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libunwind.h; path = include/libunwind.h; sourceTree = "<group>"; };
F98BEA4B0D10C13500F298D0 /* unw_getcontext.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = unw_getcontext.s; path = src/unw_getcontext.s; sourceTree = "<group>"; };
F98BEA710D10CC1700F298D0 /* Registers.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = Registers.s; path = src/Registers.s; sourceTree = "<group>"; };
F98BEABC0D121A4000F298D0 /* libuwind.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = libuwind.cxx; path = src/libuwind.cxx; sourceTree = "<group>"; };
F98BEAC40D121B7800F298D0 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/FileAbstraction.hpp; sourceTree = "<group>"; };
F98F98E311A475B300D21E1F /* libunwind.order */ = {isa = PBXFileReference; explicitFileType = sourcecode.exports; fileEncoding = 4; path = libunwind.order; sourceTree = "<group>"; };
F9AB4BC61194E18500F870C2 /* libunwind_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libunwind_priv.h; path = src/libunwind_priv.h; sourceTree = "<group>"; };
F9ABAAA91118B2BB00A06182 /* unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unwind.h; path = include/unwind.h; sourceTree = "<group>"; };
F9BFF9C60DC935360077A618 /* compact_unwind_encoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = compact_unwind_encoding.h; path = "include/mach-o/compact_unwind_encoding.h"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
F95A3D900DE3A8AA004B72E5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
08FB7794FE84155DC02AAC07 /* libunwind */ = {
isa = PBXGroup;
children = (
F90DFABC0D8A1E9B003302A1 /* include */,
08FB7795FE84155DC02AAC07 /* src */,
1AB674ADFE9D54B511CA2CBB /* Products */,
);
name = libunwind;
sourceTree = "<group>";
};
08FB7795FE84155DC02AAC07 /* src */ = {
isa = PBXGroup;
children = (
F9413A530D25D7E100B5EA0C /* AddressSpace.hpp */,
F95BE31A0D2EED80007E3672 /* CompactUnwinder.hpp */,
F94138D00D1C7AC600B5EA0C /* dwarf2.h */,
F95BE4DC0D343AB9007E3672 /* DwarfParser.hpp */,
F95BE2990D2EB9EA007E3672 /* DwarfInstructions.hpp */,
F98BEAC40D121B7800F298D0 /* FileAbstraction.hpp */,
F95DF59A0DEDD12800B8DA7A /* InternalMacros.h */,
F98BEABC0D121A4000F298D0 /* libuwind.cxx */,
F9AB4BC61194E18500F870C2 /* libunwind_priv.h */,
F9413A540D25D7E100B5EA0C /* Registers.hpp */,
F98BEA710D10CC1700F298D0 /* Registers.s */,
F98BEA4B0D10C13500F298D0 /* unw_getcontext.s */,
F94139850D25A12200B5EA0C /* UnwindCursor.hpp */,
F938B7C50F97F50D0096ACC8 /* Unwind-sjlj.c */,
F92C4CC60DC0145500EE1253 /* UnwindLevel1.c */,
F903E4D70DC16974007E8D28 /* UnwindLevel1-gcc-ext.c */,
F98F98E311A475B300D21E1F /* libunwind.order */,
);
name = src;
sourceTree = "<group>";
};
1AB674ADFE9D54B511CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
F95A3D950DE3A8AA004B72E5 /* libunwind.dylib */,
F9276F140E6E0B6100B731C9 /* libunwind.a */,
);
name = Products;
sourceTree = "<group>";
};
F90DFABC0D8A1E9B003302A1 /* include */ = {
isa = PBXGroup;
children = (
F9BFF9C60DC935360077A618 /* compact_unwind_encoding.h */,
F9ABAAA91118B2BB00A06182 /* unwind.h */,
F98BE9080D0F3D7D00F298D0 /* libunwind.h */,
);
name = include;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
F9276EFA0E6E0B6100B731C9 /* dyld-libunwind.a */ = {
isa = PBXNativeTarget;
buildConfigurationList = F9276F110E6E0B6100B731C9 /* Build configuration list for PBXNativeTarget "dyld-libunwind.a" */;
buildPhases = (
F9276EFC0E6E0B6100B731C9 /* Sources */,
);
buildRules = (
);
dependencies = (
);
name = "dyld-libunwind.a";
productName = libunwind;
productReference = F9276F140E6E0B6100B731C9 /* libunwind.a */;
productType = "com.apple.product-type.library.static";
};
F95A3D890DE3A8AA004B72E5 /* libunwind.dylib */ = {
isa = PBXNativeTarget;
buildConfigurationList = F95A3D920DE3A8AA004B72E5 /* Build configuration list for PBXNativeTarget "libunwind.dylib" */;
buildPhases = (
F95A3D8A0DE3A8AA004B72E5 /* Sources */,
F95A3D900DE3A8AA004B72E5 /* Frameworks */,
F92A25CA13C69B62008F010E /* install usr-include */,
F92A25CB13C69B62008F010E /* install usr-include-mach-o */,
);
buildRules = (
);
dependencies = (
);
name = libunwind.dylib;
productName = libunwind;
productReference = F95A3D950DE3A8AA004B72E5 /* libunwind.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
};
buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "libunwind" */;
compatibilityVersion = "Xcode 3.0";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
English,
Japanese,
French,
German,
);
mainGroup = 08FB7794FE84155DC02AAC07 /* libunwind */;
projectDirPath = "";
projectRoot = "";
targets = (
F93A98ED0EC91269000D227E /* all */,
F9276EFA0E6E0B6100B731C9 /* dyld-libunwind.a */,
F95A3D890DE3A8AA004B72E5 /* libunwind.dylib */,
);
};
/* End PBXProject section */
/* Begin PBXShellScriptBuildPhase section */
F97377A8133A82A600BDE64E /* Simulator clean up */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
files = (
);
inputPaths = (
);
name = "Simulator clean up";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
shellScript = "if [ \"${PLATFORM_NAME}\" == \"iphonesimulator\" ]\nthen\n # when simulator runs on 10.7 only, we can stop deleting usr/lib/system/libunwind.dylib\n rm -rf \"${DSTROOT}/usr\"\n rm -rf \"${DSTROOT}/$SDKROOT/usr/local\"\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
F9276EFC0E6E0B6100B731C9 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F9276EFD0E6E0B6100B731C9 /* libuwind.cxx in Sources */,
F938B7C70F97F50D0096ACC8 /* Unwind-sjlj.c in Sources */,
F9276EFE0E6E0B6100B731C9 /* UnwindLevel1.c in Sources */,
F9276F280E6E0D1400B731C9 /* UnwindLevel1-gcc-ext.c in Sources */,
F9276F000E6E0B6100B731C9 /* Registers.s in Sources */,
F9276F010E6E0B6100B731C9 /* unw_getcontext.s in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F95A3D8A0DE3A8AA004B72E5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F95A3D8B0DE3A8AA004B72E5 /* libuwind.cxx in Sources */,
F95A3D8C0DE3A8AA004B72E5 /* Registers.s in Sources */,
F95A3D8D0DE3A8AA004B72E5 /* unw_getcontext.s in Sources */,
F95A3D8E0DE3A8AA004B72E5 /* UnwindLevel1.c in Sources */,
F95A3D8F0DE3A8AA004B72E5 /* UnwindLevel1-gcc-ext.c in Sources */,
F98F98F311A47E2C00D21E1F /* Unwind-sjlj.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
F93A98F50EC9127A000D227E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F9276EFA0E6E0B6100B731C9 /* dyld-libunwind.a */;
targetProxy = F93A98F40EC9127A000D227E /* PBXContainerItemProxy */;
};
F992F1FB11A35E2F0008F9B0 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F95A3D890DE3A8AA004B72E5 /* libunwind.dylib */;
targetProxy = F992F1FA11A35E2F0008F9B0 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
1DEB914F08733D8E0010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LIBRARY = "libc++";
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
USE_HEADERMAP = NO;
};
name = Debug;
};
1DEB915008733D8E0010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LIBRARY = "libc++";
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
USE_HEADERMAP = NO;
};
name = Release;
};
F9276F120E6E0B6100B731C9 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
x86_64,
ppc,
);
GCC_ALTIVEC_EXTENSIONS = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = NO;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = FOR_DYLD;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
GCC_WARN_MISSING_PARENTHESES = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNINITIALIZED_AUTOS = NO;
GCC_WARN_UNUSED_VALUE = YES;
HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
OTHER_CFLAGS = "-fexceptions";
OTHER_CPLUSPLUSFLAGS = "-funwind-tables";
PRODUCT_NAME = unwind;
WARNING_CFLAGS = "-Wall";
};
name = Debug;
};
F9276F130E6E0B6100B731C9 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_ALTIVEC_EXTENSIONS = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = NO;
GCC_OPTIMIZATION_LEVEL = 3;
GCC_PREPROCESSOR_DEFINITIONS = (
FOR_DYLD,
NDEBUG,
);
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
INSTALL_PATH = /usr/local/lib/dyld;
OTHER_CFLAGS = "-fexceptions";
OTHER_CPLUSPLUSFLAGS = "-funwind-tables";
PRODUCT_NAME = unwind;
};
name = Release;
};
F93A98EE0EC91269000D227E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
PRODUCT_NAME = macosx;
};
name = Debug;
};
F93A98EF0EC91269000D227E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_FIX_AND_CONTINUE = NO;
PRODUCT_NAME = macosx;
ZERO_LINK = NO;
};
name = Release;
};
F95A3D930DE3A8AA004B72E5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
x86_64,
i386,
);
EXECUTABLE_EXTENSION = dylib;
GCC_ALTIVEC_EXTENSIONS = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_ENABLE_BUILTIN_FUNCTIONS = YES;
GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = NO;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "";
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
GCC_WARN_MISSING_PARENTHESES = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNINITIALIZED_AUTOS = NO;
GCC_WARN_UNUSED_VALUE = YES;
HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
INSTALL_PATH = /usr/lib/system;
INSTALL_PATH_PREFIX = "$(INSTALL_PATH_PREFIX_$(PLATFORM_NAME))";
INSTALL_PATH_PREFIX_iphonesimulator = "$(SDKROOT)";
IS_ZIPPERED = YES;
LIBSYSTEM_LIBS = "$(LIBSYSTEM_LIBS_$(PLATFORM_NAME))";
LIBSYSTEM_LIBS_iphoneos = "-lsystem_c -ldyld";
LIBSYSTEM_LIBS_iphonesimulator = "-lsystem_sim_c -ldyld_sim -Wl,-upward-lSystem";
LIBSYSTEM_LIBS_macosx = "-lsystem_malloc -lsystem_pthread -lsystem_platform -lsystem_c -ldyld -lkeymgr ";
MACH_O_TYPE = mh_dylib;
OTHER_CFLAGS = "-fexceptions";
OTHER_CPLUSPLUSFLAGS = "-funwind-tables";
OTHER_LDFLAGS = (
"-L$(SDKROOT)/usr/lib/system",
"-nodefaultlibs",
"$(LIBSYSTEM_LIBS)",
"-Wl,-umbrella,System",
);
PRODUCT_NAME = "$(PRODUCT_NAME_$(PLATFORM_NAME))";
PRODUCT_NAME_iphoneos = libunwind;
PRODUCT_NAME_iphonesimulator = libunwind_sim;
PRODUCT_NAME_macosx = libunwind;
WARNING_CFLAGS = "-Wall";
};
name = Debug;
};
F95A3D940DE3A8AA004B72E5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
GCC_ALTIVEC_EXTENSIONS = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_BUILTIN_FUNCTIONS = YES;
GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = NO;
GCC_OPTIMIZATION_LEVEL = s;
GCC_PREPROCESSOR_DEFINITIONS = NDEBUG;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
INSTALL_PATH = "$(INSTALL_PATH_PREFIX)/usr/lib/system";
INSTALL_PATH_PREFIX = "$(INSTALL_PATH_PREFIX_$(PLATFORM_NAME))";
INSTALL_PATH_PREFIX_iphonesimulator = "$(SDKROOT)";
IS_ZIPPERED = YES;
LD_DYLIB_INSTALL_NAME = "/usr/lib/system/$(PRODUCT_NAME).dylib";
LIBSYSTEM_LIBS = "$(LIBSYSTEM_LIBS_$(PLATFORM_NAME))";
LIBSYSTEM_LIBS_iphoneos = "-lsystem_c -ldyld -Wl,-upward-lSystem";
LIBSYSTEM_LIBS_iphonesimulator = "-lsystem_sim_c -ldyld_sim -Wl,-upward-lSystem";
LIBSYSTEM_LIBS_macosx = "-lsystem_malloc -lsystem_pthread -lsystem_platform -lsystem_c -ldyld -lkeymgr ";
MACH_O_TYPE = mh_dylib;
ORDER_FILE = "$(SRCROOT)/libunwind.order";
OTHER_CFLAGS = "-fexceptions";
OTHER_CPLUSPLUSFLAGS = "-funwind-tables";
OTHER_LDFLAGS = (
"-L$(SDKROOT)/usr/lib/system",
"-nodefaultlibs",
"$(LIBSYSTEM_LIBS)",
"-Wl,-umbrella,System",
"-L/usr/lib/system",
);
PRODUCT_NAME = "$(PRODUCT_NAME_$(PLATFORM_NAME))";
PRODUCT_NAME_iphoneos = libunwind;
PRODUCT_NAME_iphonesimulator = libunwind_sim;
PRODUCT_NAME_macosx = libunwind;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "libunwind" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB914F08733D8E0010E9CD /* Debug */,
1DEB915008733D8E0010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F9276F110E6E0B6100B731C9 /* Build configuration list for PBXNativeTarget "dyld-libunwind.a" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F9276F120E6E0B6100B731C9 /* Debug */,
F9276F130E6E0B6100B731C9 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F93A98F70EC91298000D227E /* Build configuration list for PBXAggregateTarget "all" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F93A98EE0EC91269000D227E /* Debug */,
F93A98EF0EC91269000D227E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F95A3D920DE3A8AA004B72E5 /* Build configuration list for PBXNativeTarget "libunwind.dylib" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F95A3D930DE3A8AA004B72E5 /* Debug */,
F95A3D940DE3A8AA004B72E5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>all.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>dyld-libunwind.a.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>libunwind.dylib.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
</dict>
</dict>
</plist>

431
src/AddressSpace.hpp Normal file
View File

@ -0,0 +1,431 @@
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
* Copyright (c) 2008-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
//
// C++ interface to lower levels of libuwind
//
#ifndef __ADDRESSSPACE_HPP__
#define __ADDRESSSPACE_HPP__
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <mach-o/loader.h>
#include <mach-o/getsect.h>
#include <mach-o/dyld_priv.h>
#include <Availability.h>
#include "FileAbstraction.hpp"
#include "libunwind.h"
#include "InternalMacros.h"
#include "dwarf2.h"
#if __i386__ && defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
// For iOS simulator to link, we need a __dyld section
// We need one to access private _dyld_func_lookup function.
struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); };
static volatile struct __DATA__dyld myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, NULL };
static int my_dyld_func_lookup(const char* dyld_func_name, void **address)
{
return (*myDyldSection.lookup)(dyld_func_name, address);
}
bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
{
static void* (*p)(void*, dyld_unwind_sections*) = NULL;
if(p == NULL)
my_dyld_func_lookup("__dyld_find_unwind_sections", (void**)&p);
return p(addr, info);
}
#endif
namespace libunwind {
///
/// LocalAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
/// in the same process. It compiles away and making local unwinds very fast.
///
class LocalAddressSpace
{
public:
#if __LP64__
typedef uint64_t pint_t;
typedef int64_t sint_t;
#else
typedef uint32_t pint_t;
typedef int32_t sint_t;
#endif
uint8_t get8(pint_t addr) { return *((uint8_t*)addr); }
uint16_t get16(pint_t addr) { return *((uint16_t*)addr); }
uint32_t get32(pint_t addr) { return *((uint32_t*)addr); }
uint64_t get64(pint_t addr) { return *((uint64_t*)addr); }
double getDouble(pint_t addr) { return *((double*)addr); }
v128 getVector(pint_t addr) { return *((v128*)addr); }
uintptr_t getP(pint_t addr);
static uint64_t getULEB128(pint_t& addr, pint_t end);
static int64_t getSLEB128(pint_t& addr, pint_t end);
pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
bool findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart);
};
LocalAddressSpace sThisAddress;
inline uintptr_t LocalAddressSpace::getP(pint_t addr)
{
#if __LP64__
return get64(addr);
#else
return get32(addr);
#endif
}
/* Read a ULEB128 into a 64-bit word. */
inline uint64_t
LocalAddressSpace::getULEB128(pint_t& addr, pint_t end)
{
const uint8_t* p = (uint8_t*)addr;
const uint8_t* pend = (uint8_t*)end;
uint64_t result = 0;
int bit = 0;
do {
uint64_t b;
if ( p == pend )
ABORT("truncated uleb128 expression");
b = *p & 0x7f;
if (bit >= 64 || b << bit >> bit != b) {
ABORT("malformed uleb128 expression");
}
else {
result |= b << bit;
bit += 7;
}
} while ( *p++ >= 0x80 );
addr = (pint_t)p;
return result;
}
/* Read a SLEB128 into a 64-bit word. */
inline int64_t
LocalAddressSpace::getSLEB128(pint_t& addr, pint_t end)
{
const uint8_t* p = (uint8_t*)addr;
int64_t result = 0;
int bit = 0;
uint8_t byte;
do {
byte = *p++;
result |= ((byte & 0x7f) << bit);
bit += 7;
} while (byte & 0x80);
// sign extend negative numbers
if ( (byte & 0x40) != 0 )
result |= (-1LL) << bit;
addr = (pint_t)p;
return result;
}
LocalAddressSpace::pint_t
LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
{
pint_t startAddr = addr;
const uint8_t* p = (uint8_t*)addr;
pint_t result;
// first get value
switch (encoding & 0x0F) {
case DW_EH_PE_ptr:
result = getP(addr);
p += sizeof(pint_t);
addr = (pint_t)p;
break;
case DW_EH_PE_uleb128:
result = getULEB128(addr, end);
break;
case DW_EH_PE_udata2:
result = get16(addr);
p += 2;
addr = (pint_t)p;
break;
case DW_EH_PE_udata4:
result = get32(addr);
p += 4;
addr = (pint_t)p;
break;
case DW_EH_PE_udata8:
result = get64(addr);
p += 8;
addr = (pint_t)p;
break;
case DW_EH_PE_sleb128:
result = getSLEB128(addr, end);
break;
case DW_EH_PE_sdata2:
result = (int16_t)get16(addr);
p += 2;
addr = (pint_t)p;
break;
case DW_EH_PE_sdata4:
result = (int32_t)get32(addr);
p += 4;
addr = (pint_t)p;
break;
case DW_EH_PE_sdata8:
result = get64(addr);
p += 8;
addr = (pint_t)p;
break;
default:
ABORT("unknown pointer encoding");
}
// then add relative offset
switch ( encoding & 0x70 ) {
case DW_EH_PE_absptr:
// do nothing
break;
case DW_EH_PE_pcrel:
result += startAddr;
break;
case DW_EH_PE_textrel:
ABORT("DW_EH_PE_textrel pointer encoding not supported");
break;
case DW_EH_PE_datarel:
ABORT("DW_EH_PE_datarel pointer encoding not supported");
break;
case DW_EH_PE_funcrel:
ABORT("DW_EH_PE_funcrel pointer encoding not supported");
break;
case DW_EH_PE_aligned:
ABORT("DW_EH_PE_aligned pointer encoding not supported");
break;
default:
ABORT("unknown pointer encoding");
break;
}
if ( encoding & DW_EH_PE_indirect )
result = getP(result);
return result;
}
inline bool LocalAddressSpace::findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart)
{
dyld_unwind_sections info;
if ( _dyld_find_unwind_sections((void*)addr, &info) ) {
mh = (pint_t)info.mh;
dwarfStart = (pint_t)info.dwarf_section;
dwarfLen = (pint_t)info.dwarf_section_length;
compactStart = (pint_t)info.compact_unwind_section;
return true;
}
return false;
}
inline bool LocalAddressSpace::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
{
dl_info dyldInfo;
if ( dladdr((void*)addr, &dyldInfo) ) {
if ( dyldInfo.dli_sname != NULL ) {
strlcpy(buf, dyldInfo.dli_sname, bufLen);
*offset = (addr - (pint_t)dyldInfo.dli_saddr);
return true;
}
}
return false;
}
#if UNW_REMOTE
///
/// OtherAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
/// in the another process. The other process can be a different endianness and a different
/// pointer size and is handled by the P template parameter.
///
template <typename P>
class OtherAddressSpace
{
public:
OtherAddressSpace(task_t task) : fTask(task) {}
typedef typename P::uint_t pint_t;
uint8_t get8(pint_t addr);
uint16_t get16(pint_t addr);
uint32_t get32(pint_t addr);
uint64_t get64(pint_t addr);
pint_t getP(pint_t addr);
uint64_t getULEB128(pint_t& addr, pint_t end);
int64_t getSLEB128(pint_t& addr, pint_t end);
pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
bool findUnwindSections(pint_t addr, unwind_sections& info);
private:
void* localCopy(pint_t addr);
task_t fTask;
};
template <typename P>
uint8_t OtherAddressSpace<P>::get8(pint_t addr)
{
return *((uint8_t*)localCopy(addr));
}
template <typename P>
uint16_t OtherAddressSpace<P>::get16(pint_t addr)
{
return P::E::get16(*(uint16_t*)localCopy(addr));
}
template <typename P>
uint32_t OtherAddressSpace<P>::get32(pint_t addr)
{
return P::E::get32(*(uint32_t*)localCopy(addr));
}
template <typename P>
uint64_t OtherAddressSpace<P>::get64(pint_t addr)
{
return P::E::get64(*(uint64_t*)localCopy(addr));
}
template <typename P>
typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr)
{
return P::getP(*(uint64_t*)localCopy(addr));
}
template <typename P>
uint64_t OtherAddressSpace<P>::getULEB128(pint_t& addr, pint_t end)
{
uintptr_t size = (end - addr);
LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr);
LocalAddressSpace::pint_t sladdr = laddr;
uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr+size);
addr += (laddr-sladdr);
return result;
}
template <typename P>
int64_t OtherAddressSpace<P>::getSLEB128(pint_t& addr, pint_t end)
{
uintptr_t size = (end - addr);
LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr);
LocalAddressSpace::pint_t sladdr = laddr;
uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr+size);
addr += (laddr-sladdr);
return result;
}
template <typename P>
void* OtherAddressSpace<P>::localCopy(pint_t addr)
{
// FIX ME
}
template <typename P>
bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
{
// FIX ME
}
///
/// unw_addr_space is the base class that abstract unw_addr_space_t type in libunwind.h points to.
///
struct unw_addr_space
{
cpu_type_t cpuType;
task_t taskPort;
};
///
/// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points to when examining
/// a 32-bit intel process.
///
struct unw_addr_space_i386 : public unw_addr_space
{
unw_addr_space_i386(task_t task) : oas(task) {}
OtherAddressSpace<Pointer32<LittleEndian> > oas;
};
///
/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t points to when examining
/// a 64-bit intel process.
///
struct unw_addr_space_x86_64 : public unw_addr_space
{
unw_addr_space_x86_64(task_t task) : oas(task) {}
OtherAddressSpace<Pointer64<LittleEndian> > oas;
};
///
/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points to when examining
/// a 32-bit PowerPC process.
///
struct unw_addr_space_ppc : public unw_addr_space
{
unw_addr_space_ppc(task_t task) : oas(task) {}
OtherAddressSpace<Pointer32<BigEndian> > oas;
};
#endif // UNW_REMOTE
} // namespace libunwind
#endif // __ADDRESSSPACE_HPP__

1028
src/CompactUnwinder.hpp Normal file

File diff suppressed because it is too large Load Diff

1740
src/DwarfInstructions.hpp Normal file

File diff suppressed because it is too large Load Diff

819
src/DwarfParser.hpp Normal file
View File

@ -0,0 +1,819 @@
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
//
// processor specific parsing of dwarf unwind instructions
//
#ifndef __DWARF_PARSER_HPP__
#define __DWARF_PARSER_HPP__
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include "libunwind.h"
#include "dwarf2.h"
#include "AddressSpace.hpp"
namespace libunwind {
///
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
/// See Dwarf Spec for details:
/// http://www.linux-foundation.org/spec/booksets/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
///
template <typename A>
class CFI_Parser
{
public:
typedef typename A::pint_t pint_t;
///
/// Information encoded in a CIE (Common Information Entry)
///
struct CIE_Info {
pint_t cieStart;
pint_t cieLength;
pint_t cieInstructions;
uint8_t pointerEncoding;
uint8_t lsdaEncoding;
uint8_t personalityEncoding;
uint8_t personalityOffsetInCIE;
pint_t personality;
int codeAlignFactor;
int dataAlignFactor;
bool isSignalFrame;
bool fdesHaveAugmentationData;
};
///
/// Information about an FDE (Frame Description Entry)
///
struct FDE_Info {
pint_t fdeStart;
pint_t fdeLength;
pint_t fdeInstructions;
pint_t pcStart;
pint_t pcEnd;
pint_t lsda;
};
///
/// Used by linker when parsing __eh_frame section
///
struct FDE_Reference {
pint_t address;
uint32_t offsetInFDE;
uint8_t encodingOfAddress;
};
struct FDE_Atom_Info {
pint_t fdeAddress;
FDE_Reference function;
FDE_Reference cie;
FDE_Reference lsda;
};
struct CIE_Atom_Info {
pint_t cieAddress;
FDE_Reference personality;
};
///
/// Information about a frame layout and registers saved determined
/// by "running" the dwarf FDE "instructions"
///
enum { kMaxRegisterNumber = 120 };
enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA,
kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression } ;
struct RegisterLocation {
RegisterSavedWhere location;
int64_t value;
};
struct PrologInfo {
uint32_t cfaRegister;
int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
int64_t cfaExpression; // CFA = expression
uint32_t spExtraArgSize;
uint32_t codeOffsetAtStackDecrement;
uint8_t registerSavedTwiceInCIE;
bool registersInOtherRegisters;
bool registerSavedMoreThanOnce;
bool cfaOffsetWasNegative;
bool sameValueUsed;
RegisterLocation savedRegisters[kMaxRegisterNumber]; // from where to restore registers
};
struct PrologInfoStackEntry {
PrologInfoStackEntry(PrologInfoStackEntry* n, const PrologInfo& i)
: next(n), info(i) {}
PrologInfoStackEntry* next;
PrologInfo info;
};
static bool findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo);
static const char* decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo);
static bool parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results);
static const char* getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies);
static uint32_t getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength);
static const char* parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo);
private:
static bool parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results);
};
///
/// Parse a FDE into a CIE_Info and an FDE_Info
///
template <typename A>
const char* CFI_Parser<A>::decodeFDE(A& addressSpace, pint_t fdeStart, FDE_Info* fdeInfo, CIE_Info* cieInfo)
{
pint_t p = fdeStart;
uint64_t cfiLength = addressSpace.get32(p);
p += 4;
if ( cfiLength == 0xffffffff ) {
// 0xffffffff means length is really next 8 bytes
cfiLength = addressSpace.get64(p);
p += 8;
}
if ( cfiLength == 0 )
return "FDE has zero length"; // end marker
uint32_t ciePointer = addressSpace.get32(p);
if ( ciePointer == 0 )
return "FDE is really a CIE"; // this is a CIE not an FDE
pint_t nextCFI = p + cfiLength;
pint_t cieStart = p-ciePointer;
const char* err = parseCIE(addressSpace, cieStart, cieInfo);
if (err != NULL)
return err;
p += 4;
// parse pc begin and range
pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
// parse rest of info
fdeInfo->lsda = 0;
// check for augmentation length
if ( cieInfo->fdesHaveAugmentationData ) {
uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
pint_t endOfAug = p + augLen;
if ( cieInfo->lsdaEncoding != 0 ) {
// peek at value (without indirection). Zero means no lsda
pint_t lsdaStart = p;
if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
// reset pointer and re-parse lsda address
p = lsdaStart;
fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
}
}
p = endOfAug;
}
fdeInfo->fdeStart = fdeStart;
fdeInfo->fdeLength = nextCFI - fdeStart;
fdeInfo->fdeInstructions = p;
fdeInfo->pcStart = pcStart;
fdeInfo->pcEnd = pcStart+pcRange;
return NULL; // success
}
///
/// Scan an eh_frame section to find an FDE for a pc
///
template <typename A>
bool CFI_Parser<A>::findFDE(A& addressSpace, pint_t pc, pint_t ehSectionStart, uint32_t sectionLength, pint_t fdeHint, FDE_Info* fdeInfo, CIE_Info* cieInfo)
{
//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
const pint_t ehSectionEnd = p + sectionLength;
while ( p < ehSectionEnd ) {
pint_t currentCFI = p;
//fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
uint64_t cfiLength = addressSpace.get32(p);
p += 4;
if ( cfiLength == 0xffffffff ) {
// 0xffffffff means length is really next 8 bytes
cfiLength = addressSpace.get64(p);
p += 8;
}
if ( cfiLength == 0 )
return false; // end marker
uint32_t id = addressSpace.get32(p);
if ( id == 0 ) {
// skip over CIEs
p += cfiLength;
}
else {
// process FDE to see if it covers pc
pint_t nextCFI = p + cfiLength;
uint32_t ciePointer = addressSpace.get32(p);
pint_t cieStart = p-ciePointer;
// validate pointer to CIE is within section
if ( (ehSectionStart <= cieStart) && (cieStart < ehSectionEnd) ) {
if ( parseCIE(addressSpace, cieStart, cieInfo) == NULL ) {
p += 4;
// parse pc begin and range
pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
//fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
// test if pc is within the function this FDE covers
if ( (pcStart < pc) && (pc <= pcStart+pcRange) ) {
// parse rest of info
fdeInfo->lsda = 0;
// check for augmentation length
if ( cieInfo->fdesHaveAugmentationData ) {
uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
pint_t endOfAug = p + augLen;
if ( cieInfo->lsdaEncoding != 0 ) {
// peek at value (without indirection). Zero means no lsda
pint_t lsdaStart = p;
if ( addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0 ) {
// reset pointer and re-parse lsda address
p = lsdaStart;
fdeInfo->lsda = addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
}
}
p = endOfAug;
}
fdeInfo->fdeStart = currentCFI;
fdeInfo->fdeLength = nextCFI - currentCFI;
fdeInfo->fdeInstructions = p;
fdeInfo->pcStart = pcStart;
fdeInfo->pcEnd = pcStart+pcRange;
//fprintf(stderr, "findFDE(pc=0x%llX) found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
return true;
}
else {
//fprintf(stderr, "findFDE(pc=0x%llX) not found with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pc, (uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
// pc is not in begin/range, skip this FDE
}
}
else {
// malformed CIE, now augmentation describing pc range encoding
//fprintf(stderr, "malformed CIE\n");
}
}
else {
// malformed FDE. CIE is bad
//fprintf(stderr, "malformed FDE, cieStart=0x%llX, ehSectionStart=0x%llX, ehSectionEnd=0x%llX\n",
// (uint64_t)cieStart, (uint64_t)ehSectionStart, (uint64_t)ehSectionEnd);
}
p = nextCFI;
}
}
//fprintf(stderr, "findFDE(pc=0x%llX) not found\n",(uint64_t)pc);
return false;
}
///
/// Extract info from a CIE
///
template <typename A>
const char* CFI_Parser<A>::parseCIE(A& addressSpace, pint_t cie, CIE_Info* cieInfo)
{
//fprintf(stderr, "parseCIE(0x%llX)\n", (long long)cie);
cieInfo->pointerEncoding = 0;
cieInfo->lsdaEncoding = 0;
cieInfo->personalityEncoding = 0;
cieInfo->personalityOffsetInCIE = 0;
cieInfo->personality = 0;
cieInfo->codeAlignFactor = 0;
cieInfo->dataAlignFactor = 0;
cieInfo->isSignalFrame = false;
cieInfo->fdesHaveAugmentationData = false;
cieInfo->cieStart = cie;
pint_t p = cie;
uint64_t cieLength = addressSpace.get32(p);
p += 4;
pint_t cieContentEnd = p + cieLength;
if ( cieLength == 0xffffffff ) {
// 0xffffffff means length is really next 8 bytes
cieLength = addressSpace.get64(p);
p += 8;
cieContentEnd = p + cieLength;
}
if ( cieLength == 0 )
return NULL;
// CIE ID is always 0
if ( addressSpace.get32(p) != 0 )
return "CIE ID is not zero";
p += 4;
// Version is always 1 or 3
uint8_t version = addressSpace.get8(p);
if ( (version != 1) && (version != 3) )
return "CIE version is not 1 or 3";
++p;
// save start of augmentation string and find end
pint_t strStart = p;
while ( addressSpace.get8(p) != 0 )
++p;
++p;
// parse code aligment factor
cieInfo->codeAlignFactor = addressSpace.getULEB128(p, cieContentEnd);
// parse data alignment factor
cieInfo->dataAlignFactor = addressSpace.getSLEB128(p, cieContentEnd);
// parse return address register
addressSpace.getULEB128(p, cieContentEnd);
// parse augmentation data based on augmentation string
const char* result = NULL;
if ( addressSpace.get8(strStart) == 'z' ) {
// parse augmentation data length
addressSpace.getULEB128(p, cieContentEnd);
for (pint_t s=strStart; addressSpace.get8(s) != '\0'; ++s) {
switch ( addressSpace.get8(s) ) {
case 'z':
cieInfo->fdesHaveAugmentationData = true;
break;
case 'P':
cieInfo->personalityEncoding = addressSpace.get8(p);
++p;
cieInfo->personalityOffsetInCIE = p-cie;
cieInfo->personality = addressSpace.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
break;
case 'L':
cieInfo->lsdaEncoding = addressSpace.get8(p);
++p;
break;
case 'R':
cieInfo->pointerEncoding = addressSpace.get8(p);
++p;
break;
case 'S':
cieInfo->isSignalFrame = true;
break;
default:
// ignore unknown letters
break;
}
}
}
cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
cieInfo->cieInstructions = p;
return result;
}
template <typename A>
uint32_t CFI_Parser<A>::getCFICount(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength)
{
uint32_t count = 0;
const pint_t ehSectionEnd = ehSectionStart + sectionLength;
for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
uint64_t cfiLength = addressSpace.get32(p);
p += 4;
if ( cfiLength == 0xffffffff ) {
// 0xffffffff means length is really next 8 bytes
cfiLength = addressSpace.get64(p);
p += 8;
}
if ( cfiLength == 0 )
return count; // end marker
++count;
p += cfiLength;
}
return count;
}
template <typename A>
const char* CFI_Parser<A>::getCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength,
std::vector<FDE_Atom_Info>& fdes, std::vector<CIE_Atom_Info>& cies)
{
const pint_t ehSectionEnd = ehSectionStart + sectionLength;
for (pint_t p=ehSectionStart; p < ehSectionEnd; ) {
pint_t currentCFI = p;
uint64_t cfiLength = addressSpace.get32(p);
p += 4;
if ( cfiLength == 0xffffffff ) {
// 0xffffffff means length is really next 8 bytes
cfiLength = addressSpace.get64(p);
p += 8;
}
if ( cfiLength == 0 )
return NULL; // end marker
uint32_t id = addressSpace.get32(p);
if ( id == 0 ) {
// is CIE
CIE_Info cieInfo;
const char* err = parseCIE(addressSpace, currentCFI, &cieInfo);
if ( err != NULL )
return err;
CIE_Atom_Info entry;
entry.cieAddress = currentCFI;
entry.personality.address = cieInfo.personality;
entry.personality.offsetInFDE = cieInfo.personalityOffsetInCIE;
entry.personality.encodingOfAddress = cieInfo.personalityEncoding;
cies.push_back(entry);
p += cfiLength;
}
else {
// is FDE
FDE_Atom_Info entry;
entry.fdeAddress = currentCFI;
entry.function.address = 0;
entry.cie.address = 0;
entry.lsda.address = 0;
pint_t nextCFI = p + cfiLength;
uint32_t ciePointer = addressSpace.get32(p);
pint_t cieStart = p-ciePointer;
// validate pointer to CIE is within section
if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) )
return "FDE points to CIE outside __eh_frame section";
CIE_Info cieInfo;
const char* err = parseCIE(addressSpace, cieStart, &cieInfo);
if ( err != NULL )
return err;
entry.cie.address = cieStart;
entry.cie.offsetInFDE = p-currentCFI;
entry.cie.encodingOfAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
p += 4;
// parse pc begin and range
pint_t offsetOfFunctionAddress = p-currentCFI;
pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
//fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
// test if pc is within the function this FDE covers
entry.function.address = pcStart;
entry.function.offsetInFDE = offsetOfFunctionAddress;
entry.function.encodingOfAddress = cieInfo.pointerEncoding;
// skip over augmentation length
if ( cieInfo.fdesHaveAugmentationData ) {
uintptr_t augLen = addressSpace.getULEB128(p, nextCFI);
pint_t endOfAug = p + augLen;
if ( (cieInfo.lsdaEncoding != 0) && (addressSpace.getP(p) != 0) ) {
pint_t offsetOfLSDAAddress = p-currentCFI;
entry.lsda.address = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding);
entry.lsda.offsetInFDE = offsetOfLSDAAddress;
entry.lsda.encodingOfAddress = cieInfo.lsdaEncoding;
}
p = endOfAug;
}
fdes.push_back(entry);
p = nextCFI;
}
}
return NULL; // success
}
///
/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
///
template <typename A>
bool CFI_Parser<A>::parseFDEInstructions(A& addressSpace, const FDE_Info& fdeInfo, const CIE_Info& cieInfo, pint_t upToPC, PrologInfo* results)
{
// clear results
bzero(results, sizeof(PrologInfo));
PrologInfoStackEntry* rememberStack = NULL;
// parse CIE then FDE instructions
return parseInstructions(addressSpace, cieInfo.cieInstructions, cieInfo.cieStart+cieInfo.cieLength,
cieInfo, (pint_t)(-1), rememberStack, results)
&& parseInstructions(addressSpace, fdeInfo.fdeInstructions, fdeInfo.fdeStart+fdeInfo.fdeLength,
cieInfo, upToPC-fdeInfo.pcStart, rememberStack, results);
}
///
/// "run" the dwarf instructions
///
template <typename A>
bool CFI_Parser<A>::parseInstructions(A& addressSpace, pint_t instructions, pint_t instructionsEnd, const CIE_Info& cieInfo,
pint_t pcoffset, PrologInfoStackEntry*& rememberStack, PrologInfo* results)
{
const bool logDwarf = false;
pint_t p = instructions;
uint32_t codeOffset = 0;
PrologInfo initialState = *results;
if ( logDwarf ) fprintf(stderr, "parseInstructions(instructions=0x%0llX)\n", (uint64_t)instructionsEnd);
// see Dwarf Spec, section 6.4.2 for details on unwind opcodes
while ( (p < instructionsEnd) && (codeOffset < pcoffset) ) {
uint64_t reg;
uint64_t reg2;
int64_t offset;
uint64_t length;
uint8_t opcode = addressSpace.get8(p);
uint8_t operand;
PrologInfoStackEntry* entry;
++p;
switch (opcode) {
case DW_CFA_nop:
if ( logDwarf ) fprintf(stderr, "DW_CFA_nop\n");
break;
case DW_CFA_set_loc:
codeOffset = addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
if ( logDwarf ) fprintf(stderr, "DW_CFA_set_loc\n");
break;
case DW_CFA_advance_loc1:
codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
p += 1;
if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc1: new offset=%u\n", codeOffset);
break;
case DW_CFA_advance_loc2:
codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
p += 2;
if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc2: new offset=%u\n", codeOffset);
break;
case DW_CFA_advance_loc4:
codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
p += 4;
if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc4: new offset=%u\n", codeOffset);
break;
case DW_CFA_offset_extended:
reg = addressSpace.getULEB128(p, instructionsEnd);
offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
return false;
}
if ( results->savedRegisters[reg].location != kRegisterUnused )
results->registerSavedMoreThanOnce = true;
results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = offset;
if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg, offset);
break;
case DW_CFA_restore_extended:
reg = addressSpace.getULEB128(p, instructionsEnd);;
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
return false;
}
results->savedRegisters[reg] = initialState.savedRegisters[reg];
if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg);
break;
case DW_CFA_undefined:
reg = addressSpace.getULEB128(p, instructionsEnd);
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_undefined dwarf unwind, reg too big\n");
return false;
}
results->savedRegisters[reg].location = kRegisterUnused;
if ( logDwarf ) fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg);
break;
case DW_CFA_same_value:
reg = addressSpace.getULEB128(p, instructionsEnd);
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_same_value dwarf unwind, reg too big\n");
return false;
}
// <rdar://problem/8456377> DW_CFA_same_value unsupported
// "same value" means register was stored in frame, but its current
// value has not changed, so no need to restore from frame.
// We model this as if the register was never saved.
results->savedRegisters[reg].location = kRegisterUnused;
// set flag to disable conversion to compact unwind
results->sameValueUsed = true;
if ( logDwarf ) fprintf(stderr, "DW_CFA_same_value(reg=%lld)\n", reg);
break;
case DW_CFA_register:
reg = addressSpace.getULEB128(p, instructionsEnd);
reg2 = addressSpace.getULEB128(p, instructionsEnd);
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg too big\n");
return false;
}
if ( reg2 > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
return false;
}
results->savedRegisters[reg].location = kRegisterInRegister;
results->savedRegisters[reg].value = reg2;
// set flag to disable conversion to compact unwind
results->registersInOtherRegisters = true;
if ( logDwarf ) fprintf(stderr, "DW_CFA_register(reg=%lld, reg2=%lld)\n", reg, reg2);
break;
case DW_CFA_remember_state:
// avoid operator new, because that would be an upward dependency
entry = (PrologInfoStackEntry*)malloc(sizeof(PrologInfoStackEntry));
if ( entry != NULL ) {
entry->next = rememberStack;
entry->info = *results;
rememberStack = entry;
}
else {
return false;
}
if ( logDwarf ) fprintf(stderr, "DW_CFA_remember_state\n");
break;
case DW_CFA_restore_state:
if ( rememberStack != NULL ) {
PrologInfoStackEntry* top = rememberStack;
*results = top->info;
rememberStack = top->next;
free((char*)top);
}
else {
return false;
}
if ( logDwarf ) fprintf(stderr, "DW_CFA_restore_state\n");
break;
case DW_CFA_def_cfa:
reg = addressSpace.getULEB128(p, instructionsEnd);
offset = addressSpace.getULEB128(p, instructionsEnd);
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
return false;
}
results->cfaRegister = reg;
results->cfaRegisterOffset = offset;
if ( offset > 0x80000000 )
results->cfaOffsetWasNegative = true;
if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset);
break;
case DW_CFA_def_cfa_register:
reg = addressSpace.getULEB128(p, instructionsEnd);
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
return false;
}
results->cfaRegister = reg;
if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg);
break;
case DW_CFA_def_cfa_offset:
results->cfaRegisterOffset = addressSpace.getULEB128(p, instructionsEnd);
results->codeOffsetAtStackDecrement = codeOffset;
if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", results->cfaRegisterOffset);
break;
case DW_CFA_def_cfa_expression:
results->cfaRegister = 0;
results->cfaExpression = p;
length = addressSpace.getULEB128(p, instructionsEnd);
p += length;
if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n",
results->cfaExpression, length);
break;
case DW_CFA_expression:
reg = addressSpace.getULEB128(p, instructionsEnd);
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_expression dwarf unwind, reg too big\n");
return false;
}
results->savedRegisters[reg].location = kRegisterAtExpression;
results->savedRegisters[reg].value = p;
length = addressSpace.getULEB128(p, instructionsEnd);
p += length;
if ( logDwarf ) fprintf(stderr, "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n",
reg, results->savedRegisters[reg].value, length);
break;
case DW_CFA_offset_extended_sf:
reg = addressSpace.getULEB128(p, instructionsEnd);
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
return false;
}
offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
if ( results->savedRegisters[reg].location != kRegisterUnused )
results->registerSavedMoreThanOnce = true;
results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = offset;
if ( logDwarf ) fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n", reg, offset);
break;
case DW_CFA_def_cfa_sf:
reg = addressSpace.getULEB128(p, instructionsEnd);
offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
return false;
}
results->cfaRegister = reg;
results->cfaRegisterOffset = offset;
if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg, offset);
break;
case DW_CFA_def_cfa_offset_sf:
results->cfaRegisterOffset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
results->codeOffsetAtStackDecrement = codeOffset;
if ( logDwarf ) fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", results->cfaRegisterOffset);
break;
case DW_CFA_val_offset:
reg = addressSpace.getULEB128(p, instructionsEnd);
offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
results->savedRegisters[reg].value = offset;
if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg, offset);
break;
case DW_CFA_val_offset_sf:
reg = addressSpace.getULEB128(p, instructionsEnd);
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
return false;
}
offset = addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
results->savedRegisters[reg].value = offset;
if ( logDwarf ) fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg, offset);
break;
case DW_CFA_val_expression:
reg = addressSpace.getULEB128(p, instructionsEnd);
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
return false;
}
results->savedRegisters[reg].location = kRegisterIsExpression;
results->savedRegisters[reg].value = p;
length = addressSpace.getULEB128(p, instructionsEnd);
p += length;
if ( logDwarf ) fprintf(stderr, "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n",
reg, results->savedRegisters[reg].value, length);
break;
case DW_CFA_GNU_args_size:
offset = addressSpace.getULEB128(p, instructionsEnd);
results->spExtraArgSize = offset;
if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", offset);
break;
case DW_CFA_GNU_negative_offset_extended:
reg = addressSpace.getULEB128(p, instructionsEnd);
if ( reg > kMaxRegisterNumber ) {
fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf unwind, reg too big\n");
return false;
}
offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
if ( results->savedRegisters[reg].location != kRegisterUnused )
results->registerSavedMoreThanOnce = true;
results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = -offset;
if ( logDwarf ) fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset);
break;
default:
operand = opcode & 0x3F;
switch ( opcode & 0xC0 ) {
case DW_CFA_offset:
reg = operand;
offset = addressSpace.getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
if ( results->savedRegisters[reg].location != kRegisterUnused ) {
// look for idiom of PC saved twice in CIE to mean disable compact unwind encoding
if ( (pcoffset == (pint_t)(-1))
&& (results->savedRegisters[reg].location == kRegisterInCFA)
&& (results->savedRegisters[reg].value == offset) )
results->registerSavedTwiceInCIE = reg;
else
results->registerSavedMoreThanOnce = true;
}
results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = offset;
if ( logDwarf ) fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand, offset);
break;
case DW_CFA_advance_loc:
codeOffset += operand * cieInfo.codeAlignFactor;
if ( logDwarf ) fprintf(stderr, "DW_CFA_advance_loc: new offset=%u\n", codeOffset);
break;
case DW_CFA_restore:
// <rdar://problem/7503075> Python crashes when handling an exception thrown by an obj-c object
// libffi uses DW_CFA_restore in the middle of some custom dwarf, so it is not a good epilog flag
//return true; // gcc-4.5 starts the epilog with this
reg = operand;
results->savedRegisters[reg] = initialState.savedRegisters[reg];
if ( logDwarf ) fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg);
break;
default:
if ( logDwarf ) fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
return false;
}
}
}
return true;
}
} // namespace libunwind
#endif // __DWARF_PARSER_HPP__

146
src/FileAbstraction.hpp Normal file
View File

@ -0,0 +1,146 @@
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
* Copyright (c) 2005-2008 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef __FILE_ABSTRACTION__
#define __FILE_ABSTRACTION__
#include <stdint.h>
#include <string.h>
#include <libkern/OSByteOrder.h>
#ifdef __OPTIMIZE__
#define INLINE __attribute__((always_inline))
#else
#define INLINE
#endif
//
// This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants
//
// For example: to make a utility that handles 32-bit little enidan files use: Pointer32<LittleEndian>
//
//
// get16() read a 16-bit number from an E endian struct
// set16() write a 16-bit number to an E endian struct
// get32() read a 32-bit number from an E endian struct
// set32() write a 32-bit number to an E endian struct
// get64() read a 64-bit number from an E endian struct
// set64() write a 64-bit number to an E endian struct
//
// getBits() read a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
// setBits() write a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
//
// getBitsRaw() read a bit field from a struct with native endianness
// setBitsRaw() write a bit field from a struct with native endianness
//
class BigEndian
{
public:
static uint16_t get16(const uint16_t& from) INLINE { return OSReadBigInt16(&from, 0); }
static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteBigInt16(&into, 0, value); }
static uint32_t get32(const uint32_t& from) INLINE { return OSReadBigInt32(&from, 0); }
static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteBigInt32(&into, 0, value); }
static uint64_t get64(const uint64_t& from) INLINE { return OSReadBigInt64(&from, 0); }
static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteBigInt64(&into, 0, value); }
static uint32_t getBits(const uint32_t& from,
uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
static void setBits(uint32_t& into, uint32_t value,
uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
static uint32_t getBitsRaw(const uint32_t& from,
uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> (32-firstBit-bitCount)) & ((1<<bitCount)-1)); }
static void setBitsRaw(uint32_t& into, uint32_t value,
uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
const uint32_t mask = ((1<<bitCount)-1);
temp &= ~(mask << (32-firstBit-bitCount));
temp |= ((value & mask) << (32-firstBit-bitCount));
into = temp; }
enum { little_endian = 0 };
};
class LittleEndian
{
public:
static uint16_t get16(const uint16_t& from) INLINE { return OSReadLittleInt16(&from, 0); }
static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteLittleInt16(&into, 0, value); }
static uint32_t get32(const uint32_t& from) INLINE { return OSReadLittleInt32(&from, 0); }
static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteLittleInt32(&into, 0, value); }
static uint64_t get64(const uint64_t& from) INLINE { return OSReadLittleInt64(&from, 0); }
static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteLittleInt64(&into, 0, value); }
static uint32_t getBits(const uint32_t& from,
uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
static void setBits(uint32_t& into, uint32_t value,
uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
static uint32_t getBitsRaw(const uint32_t& from,
uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> firstBit) & ((1<<bitCount)-1)); }
static void setBitsRaw(uint32_t& into, uint32_t value,
uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
const uint32_t mask = ((1<<bitCount)-1);
temp &= ~(mask << firstBit);
temp |= ((value & mask) << firstBit);
into = temp; }
enum { little_endian = 1 };
};
template <typename _E>
class Pointer32
{
public:
typedef uint32_t uint_t;
typedef _E E;
static uint64_t getP(const uint_t& from) INLINE { return _E::get32(from); }
static void setP(uint_t& into, uint64_t value) INLINE { _E::set32(into, value); }
};
template <typename _E>
class Pointer64
{
public:
typedef uint64_t uint_t;
typedef _E E;
static uint64_t getP(const uint_t& from) INLINE { return _E::get64(from); }
static void setP(uint_t& into, uint64_t value) INLINE { _E::set64(into, value); }
};
#endif // __FILE_ABSTRACTION__

104
src/InternalMacros.h Normal file
View File

@ -0,0 +1,104 @@
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
* Copyright (c) 2008-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef INTERNAL_MACROS_H
#define INTERNAL_MACROS_H
#include <assert.h>
#include <Availability.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void __assert_rtn(const char *, const char *, int, const char *) __attribute__((noreturn));
#ifdef __cplusplus
}
#endif
#define UNW_STEP_SUCCESS 1
#define UNW_STEP_END 0
struct v128 { unsigned int vec[4]; };
#define EXPORT __attribute__((visibility("default")))
#define COMPILE_TIME_ASSERT( expr ) \
extern int compile_time_assert_failed[ ( expr ) ? 1 : -1 ] __attribute__( ( unused ) );
#define ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg)
#if NDEBUG
#define DEBUG_MESSAGE(msg, ...)
#define DEBUG_PRINT_API(msg, ...)
#define DEBUG_PRINT_UNWINDING_TEST 0
#define DEBUG_PRINT_UNWINDING(msg, ...)
#define DEBUG_LOG_NON_ZERO(x) x;
#define INITIALIZE_DEBUG_PRINT_API
#define INITIALIZE_DEBUG_PRINT_UNWINDING
#else
#define DEBUG_MESSAGE(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__)
#ifdef __cplusplus
extern "C" {
#endif
extern bool logAPIs();
extern bool logUnwinding();
#ifdef __cplusplus
}
#endif
#define DEBUG_LOG_NON_ZERO(x) { int _err = x; if ( _err != 0 ) fprintf(stderr, "libuwind: " #x "=%d in %s", _err, __FUNCTION__); }
#define DEBUG_PRINT_API(msg, ...) do { if ( logAPIs() ) fprintf(stderr, msg, __VA_ARGS__); } while(0)
#define DEBUG_PRINT_UNWINDING(msg, ...) do { if ( logUnwinding() ) fprintf(stderr, msg, __VA_ARGS__); } while(0)
#define DEBUG_PRINT_UNWINDING_TEST logUnwinding()
#define INITIALIZE_DEBUG_PRINT_API bool logAPIs() { static bool log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); return log; }
#define INITIALIZE_DEBUG_PRINT_UNWINDING bool logUnwinding() { static bool log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); return log; }
#endif
// static linker symbols to prevent wrong two level namespace for _Unwind symbols
#if __arm__
#define NOT_HERE_BEFORE_5_0(sym) \
extern const char sym##_tmp30 __asm("$ld$hide$os3.0$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp30 = 0; \
extern const char sym##_tmp31 __asm("$ld$hide$os3.1$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp31 = 0; \
extern const char sym##_tmp32 __asm("$ld$hide$os3.2$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp32 = 0; \
extern const char sym##_tmp40 __asm("$ld$hide$os4.0$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp40 = 0; \
extern const char sym##_tmp41 __asm("$ld$hide$os4.1$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp41 = 0; \
extern const char sym##_tmp42 __asm("$ld$hide$os4.2$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp42 = 0; \
extern const char sym##_tmp43 __asm("$ld$hide$os4.3$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp43 = 0;
#endif
#define NOT_HERE_BEFORE_10_6(sym) \
extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
#define NEVER_HERE(sym) \
extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
#endif // INTERNAL_MACROS_H

261
src/Registers.S Normal file
View File

@ -0,0 +1,261 @@
#if __i386__
.text
.globl __ZN9libunwind13Registers_x866jumptoEv
.private_extern __ZN9libunwind13Registers_x866jumptoEv
__ZN9libunwind13Registers_x866jumptoEv:
#
# void libunwind::Registers_x86::jumpto()
#
# On entry:
# + +
# +-----------------------+
# + thread_state pointer +
# +-----------------------+
# + return address +
# +-----------------------+ <-- SP
# + +
movl 4(%esp), %eax
# set up eax and ret on new stack location
movl 28(%eax), %edx # edx holds new stack pointer
subl $8,%edx
movl %edx, 28(%eax)
movl 0(%eax), %ebx
movl %ebx, 0(%edx)
movl 40(%eax), %ebx
movl %ebx, 4(%edx)
# we now have ret and eax pushed onto where new stack will be
# restore all registers
movl 4(%eax), %ebx
movl 8(%eax), %ecx
movl 12(%eax), %edx
movl 16(%eax), %edi
movl 20(%eax), %esi
movl 24(%eax), %ebp
movl 28(%eax), %esp
# skip ss
# skip eflags
pop %eax # eax was already pushed on new stack
ret # eip was already pushed on new stack
# skip cs
# skip ds
# skip es
# skip fs
# skip gs
#elif __x86_64__
.text
.globl __ZN9libunwind16Registers_x86_646jumptoEv
.private_extern __ZN9libunwind16Registers_x86_646jumptoEv
__ZN9libunwind16Registers_x86_646jumptoEv:
#
# void libunwind::Registers_x86_64::jumpto()
#
# On entry, thread_state pointer is in rdi
movq 56(%rdi), %rax # rax holds new stack pointer
subq $16, %rax
movq %rax, 56(%rdi)
movq 32(%rdi), %rbx # store new rdi on new stack
movq %rbx, 0(%rax)
movq 128(%rdi), %rbx # store new rip on new stack
movq %rbx, 8(%rax)
# restore all registers
movq 0(%rdi), %rax
movq 8(%rdi), %rbx
movq 16(%rdi), %rcx
movq 24(%rdi), %rdx
# restore rdi later
movq 40(%rdi), %rsi
movq 48(%rdi), %rbp
# restore rsp later
movq 64(%rdi), %r8
movq 72(%rdi), %r9
movq 80(%rdi), %r10
movq 88(%rdi), %r11
movq 96(%rdi), %r12
movq 104(%rdi), %r13
movq 112(%rdi), %r14
movq 120(%rdi), %r15
# skip rflags
# skip cs
# skip fs
# skip gs
movq 56(%rdi), %rsp # cut back rsp to new location
pop %rdi # rdi was saved here earlier
ret # rip was saved here
#elif __ppc__
.text
.globl __ZN9libunwind13Registers_ppc6jumptoEv
.private_extern __ZN9libunwind13Registers_ppc6jumptoEv
__ZN9libunwind13Registers_ppc6jumptoEv:
;
; void libunwind::Registers_ppc::jumpto()
;
; On entry:
; thread_state pointer is in r3
;
; restore integral registerrs
; skip r0 for now
; skip r1 for now
lwz r2, 16(r3)
; skip r3 for now
; skip r4 for now
; skip r5 for now
lwz r6, 32(r3)
lwz r7, 36(r3)
lwz r8, 40(r3)
lwz r9, 44(r3)
lwz r10, 48(r3)
lwz r11, 52(r3)
lwz r12, 56(r3)
lwz r13, 60(r3)
lwz r14, 64(r3)
lwz r15, 68(r3)
lwz r16, 72(r3)
lwz r17, 76(r3)
lwz r18, 80(r3)
lwz r19, 84(r3)
lwz r20, 88(r3)
lwz r21, 92(r3)
lwz r22, 96(r3)
lwz r23,100(r3)
lwz r24,104(r3)
lwz r25,108(r3)
lwz r26,112(r3)
lwz r27,116(r3)
lwz r28,120(r3)
lwz r29,124(r3)
lwz r30,128(r3)
lwz r31,132(r3)
; restore float registers
lfd f0, 160(r3)
lfd f1, 168(r3)
lfd f2, 176(r3)
lfd f3, 184(r3)
lfd f4, 192(r3)
lfd f5, 200(r3)
lfd f6, 208(r3)
lfd f7, 216(r3)
lfd f8, 224(r3)
lfd f9, 232(r3)
lfd f10,240(r3)
lfd f11,248(r3)
lfd f12,256(r3)
lfd f13,264(r3)
lfd f14,272(r3)
lfd f15,280(r3)
lfd f16,288(r3)
lfd f17,296(r3)
lfd f18,304(r3)
lfd f19,312(r3)
lfd f20,320(r3)
lfd f21,328(r3)
lfd f22,336(r3)
lfd f23,344(r3)
lfd f24,352(r3)
lfd f25,360(r3)
lfd f26,368(r3)
lfd f27,376(r3)
lfd f28,384(r3)
lfd f29,392(r3)
lfd f30,400(r3)
lfd f31,408(r3)
; restore vector registers if any are in use
lwz r5,156(r3) ; test VRsave
cmpwi r5,0
beq Lnovec
subi r4,r1,16
rlwinm r4,r4,0,0,27 ; mask low 4-bits
; r4 is now a 16-byte aligned pointer into the red zone
; the fVectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
#define LOAD_VECTOR_UNALIGNEDl(_index) \
andis. r0,r5,(1<<(15-_index)) @\
beq Ldone ## _index @\
lwz r0, 424+_index*16(r3) @\
stw r0, 0(r4) @\
lwz r0, 424+_index*16+4(r3) @\
stw r0, 4(r4) @\
lwz r0, 424+_index*16+8(r3) @\
stw r0, 8(r4) @\
lwz r0, 424+_index*16+12(r3)@\
stw r0, 12(r4) @\
lvx v ## _index,0,r4 @\
Ldone ## _index:
#define LOAD_VECTOR_UNALIGNEDh(_index) \
andi. r0,r5,(1<<(31-_index)) @\
beq Ldone ## _index @\
lwz r0, 424+_index*16(r3) @\
stw r0, 0(r4) @\
lwz r0, 424+_index*16+4(r3) @\
stw r0, 4(r4) @\
lwz r0, 424+_index*16+8(r3) @\
stw r0, 8(r4) @\
lwz r0, 424+_index*16+12(r3)@\
stw r0, 12(r4) @\
lvx v ## _index,0,r4 @\
Ldone ## _index:
LOAD_VECTOR_UNALIGNEDl(0)
LOAD_VECTOR_UNALIGNEDl(1)
LOAD_VECTOR_UNALIGNEDl(2)
LOAD_VECTOR_UNALIGNEDl(3)
LOAD_VECTOR_UNALIGNEDl(4)
LOAD_VECTOR_UNALIGNEDl(5)
LOAD_VECTOR_UNALIGNEDl(6)
LOAD_VECTOR_UNALIGNEDl(7)
LOAD_VECTOR_UNALIGNEDl(8)
LOAD_VECTOR_UNALIGNEDl(9)
LOAD_VECTOR_UNALIGNEDl(10)
LOAD_VECTOR_UNALIGNEDl(11)
LOAD_VECTOR_UNALIGNEDl(12)
LOAD_VECTOR_UNALIGNEDl(13)
LOAD_VECTOR_UNALIGNEDl(14)
LOAD_VECTOR_UNALIGNEDl(15)
LOAD_VECTOR_UNALIGNEDh(16)
LOAD_VECTOR_UNALIGNEDh(17)
LOAD_VECTOR_UNALIGNEDh(18)
LOAD_VECTOR_UNALIGNEDh(19)
LOAD_VECTOR_UNALIGNEDh(20)
LOAD_VECTOR_UNALIGNEDh(21)
LOAD_VECTOR_UNALIGNEDh(22)
LOAD_VECTOR_UNALIGNEDh(23)
LOAD_VECTOR_UNALIGNEDh(24)
LOAD_VECTOR_UNALIGNEDh(25)
LOAD_VECTOR_UNALIGNEDh(26)
LOAD_VECTOR_UNALIGNEDh(27)
LOAD_VECTOR_UNALIGNEDh(28)
LOAD_VECTOR_UNALIGNEDh(29)
LOAD_VECTOR_UNALIGNEDh(30)
LOAD_VECTOR_UNALIGNEDh(31)
Lnovec:
lwz r0, 136(r3) ; __cr
mtocrf 255,r0
lwz r0, 148(r3) ; __ctr
mtctr r0
lwz r0, 0(r3) ; __ssr0
mtctr r0
lwz r0, 8(r3) ; do r0 now
lwz r5,28(r3) ; do r5 now
lwz r4,24(r3) ; do r4 now
lwz r1,12(r3) ; do sp now
lwz r3,20(r3) ; do r3 last
bctr
#endif

1093
src/Registers.hpp Normal file

File diff suppressed because it is too large Load Diff

491
src/Unwind-sjlj.c Normal file
View File

@ -0,0 +1,491 @@
/* -*- mode: C++; c-basic-offset: 4; -*-
*
* Copyright (c) 2008-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*
* Implements setjump-longjump based C++ exceptions
*
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <setjmp.h>
#if !FOR_DYLD
#include <System/pthread_machdep.h>
#endif
#include "unwind.h"
#include "InternalMacros.h"
//
// ARM uses setjump/longjump based C++ exceptions.
// Other architectures use "zero cost" exceptions.
//
// With SJLJ based exceptions any function that has a catch clause or needs to do any clean up when
// an exception propagates through it, needs to call _Unwind_SjLj_Register() at the start of the
// function and _Unwind_SjLj_Unregister() at the end. The register function is called with the
// address of a block of memory in the function's stack frame. The runtime keeps a linked list
// (stack) of these blocks - one per thread. The calling function also sets the personality
// and lsda fields of the block.
//
//
#if __arm__
struct _Unwind_FunctionContext
{
// next function in stack of handlers
struct _Unwind_FunctionContext* prev;
// set by calling function before registering to be the landing pad
uintptr_t resumeLocation;
// set by personality handler to be parameters passed to landing pad function
uintptr_t resumeParameters[4];
// set by calling function before registering
__personality_routine personality; // arm offset=24
uintptr_t lsda; // arm offset=28
// variable length array, contains registers to restore
// 0 = r7, 1 = pc, 2 = sp
void* jbuf[];
};
#if FOR_DYLD
// implemented in dyld
extern struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack();
extern void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc);
#else
static struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack()
{
return (struct _Unwind_FunctionContext*)_pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
}
static void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc)
{
_pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);
}
#endif
//
// Called at start of each function that catches exceptions
//
EXPORT void _Unwind_SjLj_Register(struct _Unwind_FunctionContext* fc)
{
fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();
__Unwind_SjLj_SetTopOfFunctionStack(fc);
}
//
// Called at end of each function that catches exceptions
//
EXPORT void _Unwind_SjLj_Unregister(struct _Unwind_FunctionContext* fc)
{
__Unwind_SjLj_SetTopOfFunctionStack(fc->prev);
}
static _Unwind_Reason_Code unwind_phase1(struct _Unwind_Exception* exception_object)
{
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
DEBUG_PRINT_UNWINDING("unwind_phase1: initial function-context=%p\n", c);
// walk each frame looking for a place to stop
for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
// check for no more frames
if ( c == NULL ) {
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): reached bottom => _URC_END_OF_STACK\n", exception_object);
return _URC_END_OF_STACK;
}
DEBUG_PRINT_UNWINDING("unwind_phase1: function-context=%p\n", c);
// if there is a personality routine, ask it if it will want to stop at this frame
if ( c->personality != NULL ) {
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): calling personality function %p\n", exception_object, c->personality);
_Unwind_Reason_Code personalityResult = (*c->personality)(1, _UA_SEARCH_PHASE,
exception_object->exception_class, exception_object,
(struct _Unwind_Context*)c);
switch ( personalityResult ) {
case _URC_HANDLER_FOUND:
// found a catch clause or locals that need destructing in this frame
// stop search and remember function context
handlerNotFound = false;
exception_object->private_2 = (uintptr_t)c;
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object);
return _URC_NO_REASON;
case _URC_CONTINUE_UNWIND:
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
// continue unwinding
break;
default:
// something went wrong
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object);
return _URC_FATAL_PHASE1_ERROR;
}
}
}
return _URC_NO_REASON;
}
static _Unwind_Reason_Code unwind_phase2(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
// walk each frame until we reach where search phase said to stop
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
while ( true ) {
DEBUG_PRINT_UNWINDING("unwind_phase2s(ex_ojb=%p): function-context=%p\n", exception_object, c);
// check for no more frames
if ( c == NULL ) {
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
return _URC_END_OF_STACK;
}
// if there is a personality routine, tell it we are unwinding
if ( c->personality != NULL ) {
_Unwind_Action action = _UA_CLEANUP_PHASE;
if ( (uintptr_t)c == exception_object->private_2 )
action = (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME); // tell personality this was the frame it marked in phase 1
_Unwind_Reason_Code personalityResult = (*c->personality)(1, action,
exception_object->exception_class, exception_object,
(struct _Unwind_Context*)c);
switch ( personalityResult ) {
case _URC_CONTINUE_UNWIND:
// continue unwinding
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
if ( (uintptr_t)c == exception_object->private_2 ) {
// phase 1 said we would stop at this frame, but we did not...
ABORT("during phase1 personality function said it would stop here, but now if phase2 it did not stop here");
}
break;
case _URC_INSTALL_CONTEXT:
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT, will resume at landing pad %p\n", exception_object, c->jbuf[1]);
// personality routine says to transfer control to landing pad
// we may get control back if landing pad calls _Unwind_Resume()
__Unwind_SjLj_SetTopOfFunctionStack(c);
__builtin_longjmp(c->jbuf, 1);
// unw_resume() only returns if there was an error
return _URC_FATAL_PHASE2_ERROR;
default:
// something went wrong
DEBUG_MESSAGE("personality function returned unknown result %d", personalityResult);
return _URC_FATAL_PHASE2_ERROR;
}
}
c = c->prev;
}
// clean up phase did not resume at the frame that the search phase said it would
return _URC_FATAL_PHASE2_ERROR;
}
static _Unwind_Reason_Code unwind_phase2_forced(struct _Unwind_Exception* exception_object,
_Unwind_Stop_Fn stop, void* stop_parameter)
{
// walk each frame until we reach where search phase said to stop
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
while ( true ) {
// get next frame (skip over first which is _Unwind_RaiseException)
if ( c == NULL ) {
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
return _URC_END_OF_STACK;
}
// call stop function at each frame
_Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE);
_Unwind_Reason_Code stopResult = (*stop)(1, action,
exception_object->exception_class, exception_object,
(struct _Unwind_Context*)c, stop_parameter);
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult);
if ( stopResult != _URC_NO_REASON ) {
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object);
return _URC_FATAL_PHASE2_ERROR;
}
// if there is a personality routine, tell it we are unwinding
if ( c->personality != NULL ) {
__personality_routine p = (__personality_routine)c->personality;
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p);
_Unwind_Reason_Code personalityResult = (*p)(1, action,
exception_object->exception_class, exception_object,
(struct _Unwind_Context*)c);
switch ( personalityResult ) {
case _URC_CONTINUE_UNWIND:
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_CONTINUE_UNWIND\n", exception_object);
// destructors called, continue unwinding
break;
case _URC_INSTALL_CONTEXT:
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_INSTALL_CONTEXT\n", exception_object);
// we may get control back if landing pad calls _Unwind_Resume()
__Unwind_SjLj_SetTopOfFunctionStack(c);
__builtin_longjmp(c->jbuf, 1);
break;
default:
// something went wrong
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n",
exception_object, personalityResult);
return _URC_FATAL_PHASE2_ERROR;
}
}
c = c->prev;
}
// call stop function one last time and tell it we've reached the end of the stack
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop function with _UA_END_OF_STACK\n", exception_object);
_Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE|_UA_END_OF_STACK);
(*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context*)c, stop_parameter);
// clean up phase did not resume at the frame that the search phase said it would
return _URC_FATAL_PHASE2_ERROR;
}
//
// Called by __cxa_throw. Only returns if there is a fatal error
//
EXPORT _Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_API("_Unwind_SjLj_RaiseException(ex_obj=%p)\n", exception_object);
// mark that this is a non-forced unwind, so _Unwind_Resume() can do the right thing
exception_object->private_1 = 0;
exception_object->private_2 = 0;
// phase 1: the search phase
_Unwind_Reason_Code phase1 = unwind_phase1(exception_object);
if ( phase1 != _URC_NO_REASON )
return phase1;
// phase 2: the clean up phase
return unwind_phase2(exception_object);
}
//
// When _Unwind_RaiseException() is in phase2, it hands control
// to the personality function at each frame. The personality
// may force a jump to a landing pad in that function, the landing
// pad code may then call _Unwind_Resume() to continue with the
// unwinding. Note: the call to _Unwind_Resume() is from compiler
// geneated user code. All other _Unwind_* routines are called
// by the C++ runtime __cxa_* routines.
//
// Re-throwing an exception is implemented by having the code call
// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
//
EXPORT void _Unwind_SjLj_Resume(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_API("_Unwind_SjLj_Resume(ex_obj=%p)\n", exception_object);
if ( exception_object->private_1 != 0 )
unwind_phase2_forced(exception_object, (_Unwind_Stop_Fn)exception_object->private_1, (void*)exception_object->private_2);
else
unwind_phase2(exception_object);
// clients assume _Unwind_Resume() does not return, so all we can do is abort.
ABORT("_Unwind_SjLj_Resume() can't return");
}
//
// Called by __cxa_rethrow()
//
EXPORT _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n", exception_object, exception_object->private_1);
// if this is non-forced and a stopping place was found, then this is a re-throw
// call _Unwind_RaiseException() as if this was a new exception
if ( exception_object->private_1 == 0 ) {
return _Unwind_SjLj_RaiseException(exception_object);
// should return if there is no catch clause, so that __cxa_rethrow can call std::terminate()
}
// call through to _Unwind_Resume() which distiguishes between forced and regular exceptions
_Unwind_SjLj_Resume(exception_object);
ABORT("__Unwind_SjLj_Resume_or_Rethrow() called _Unwind_SjLj_Resume() which unexpectedly returned");
}
//
// Called by personality handler during phase 2 to get LSDA for current frame
//
EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context)
{
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%0lX\n", context, ufc->lsda);
return ufc->lsda;
}
//
// Called by personality handler during phase 2 to get register values
//
EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index)
{
DEBUG_PRINT_API("_Unwind_GetGR(context=%p, reg=%d)\n", context, index);
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
return ufc->resumeParameters[index];
}
//
// Called by personality handler during phase 2 to alter register values
//
EXPORT void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value)
{
DEBUG_PRINT_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)\n", context, index, new_value);
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
ufc->resumeParameters[index] = new_value;
}
//
// Called by personality handler during phase 2 to get instruction pointer
//
EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context* context)
{
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
DEBUG_PRINT_API("_Unwind_GetIP(context=%p) => 0x%lX\n", context, ufc->resumeLocation+1);
return ufc->resumeLocation+1;
}
//
// Called by personality handler during phase 2 to get instruction pointer
// ipBefore is a boolean that says if IP is already adjusted to be the call
// site address. Normally IP is the return address.
//
EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore)
{
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
*ipBefore = 0;
DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX\n", context, ipBefore, ufc->resumeLocation+1);
return ufc->resumeLocation+1;
}
//
// Called by personality handler during phase 2 to alter instruction pointer
//
EXPORT void _Unwind_SetIP(struct _Unwind_Context* context, uintptr_t new_value)
{
DEBUG_PRINT_API("_Unwind_SetIP(context=%p, value=0x%0lX)\n", context, new_value);
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
ufc->resumeLocation = new_value-1;
}
//
// Called by personality handler during phase 2 to find the start of the function
//
EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context)
{
// Not supported or needed for sjlj based unwinding
DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p)\n", context);
return 0;
}
//
// Called by personality handler during phase 2 if a foreign exception is caught
//
EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object);
if ( exception_object->exception_cleanup != NULL )
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object);
}
//
// Called by personality handler during phase 2 to get base address for data relative encodings
//
EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context)
{
// Not supported or needed for sjlj based unwinding
DEBUG_PRINT_API("_Unwind_GetDataRelBase(context=%p)\n", context);
ABORT("_Unwind_GetDataRelBase() not implemented");
}
//
// Called by personality handler during phase 2 to get base address for text relative encodings
//
EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context)
{
// Not supported or needed for sjlj based unwinding
DEBUG_PRINT_API("_Unwind_GetTextRelBase(context=%p)\n", context);
ABORT("_Unwind_GetTextRelBase() not implemented");
}
//
// Called by personality handler to get Call Frame Area for current frame
//
EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context* context)
{
DEBUG_PRINT_API("_Unwind_GetCFA(context=%p)\n", context);
if ( context != NULL ) {
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t)context;
// setjmp/longjmp based exceptions don't have a true CFA
// the SP in the jmpbuf is the closest approximation
return (uintptr_t)ufc->jbuf[2];
}
return 0;
}
#if !FOR_DYLD && __IPHONE_OS_VERSION_MIN_REQUIRED
//
// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in earlier versions
//
NOT_HERE_BEFORE_5_0(_Unwind_GetLanguageSpecificData)
NOT_HERE_BEFORE_5_0(_Unwind_GetRegionStart)
NOT_HERE_BEFORE_5_0(_Unwind_GetIP)
NOT_HERE_BEFORE_5_0(_Unwind_SetGR)
NOT_HERE_BEFORE_5_0(_Unwind_SetIP)
NOT_HERE_BEFORE_5_0(_Unwind_DeleteException)
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Register)
NOT_HERE_BEFORE_5_0(_Unwind_GetGR)
NOT_HERE_BEFORE_5_0(_Unwind_GetIPInfo)
NOT_HERE_BEFORE_5_0(_Unwind_GetCFA)
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume)
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException)
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow)
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister)
#endif // !FOR_DYLD
#endif // __arm__

912
src/UnwindCursor.hpp Normal file
View File

@ -0,0 +1,912 @@
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
* Copyright (c) 2007-2009 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
//
// C++ interface to lower levels of libuwind
//
#ifndef __UNWINDCURSOR_HPP__
#define __UNWINDCURSOR_HPP__
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <Availability.h>
#include "libunwind.h"
#include "AddressSpace.hpp"
#include "Registers.hpp"
#include "DwarfInstructions.hpp"
#include "CompactUnwinder.hpp"
#include "InternalMacros.h"
#if __MAC_OS_X_VERSION_MIN_REQUIRED
#define KEYMGR_SUPPPORT 1
#else
#define KEYMGR_SUPPPORT 0
#endif
#if KEYMGR_SUPPPORT
// private keymgr stuff
#define KEYMGR_GCC3_DW2_OBJ_LIST 302
extern "C" {
extern void _keymgr_set_and_unlock_processwide_ptr(int key, void* ptr);
extern void* _keymgr_get_and_lock_processwide_ptr(int key);
};
// undocumented libgcc "struct object"
struct libgcc_object
{
void* start;
void* unused1;
void* unused2;
void* fde;
unsigned long encoding;
void* fde_end;
libgcc_object* next;
};
// undocumented libgcc "struct km_object_info" referenced by KEYMGR_GCC3_DW2_OBJ_LIST
struct libgcc_object_info {
struct libgcc_object* seen_objects;
struct libgcc_object* unseen_objects;
unsigned spare[2];
};
#endif // KEYMGR_SUPPPORT
namespace libunwind {
#if !FOR_DYLD
template <typename A>
class DwarfFDECache
{
public:
typedef typename A::pint_t pint_t;
static pint_t findFDE(pint_t mh, pint_t pc);
static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde);
static void removeAllIn(pint_t mh);
static void iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
private:
static void dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide);
struct entry { pint_t mh; pint_t ip_start; pint_t ip_end; pint_t fde; };
// these fields are all static to avoid needing an initializer
// there is only one instance of this class per process
static pthread_rwlock_t fgLock;
static bool fgRegisteredForDyldUnloads;
// can't use std::vector<> here because this code must live in libSystem.dylib (which is below libstdc++.dylib)
static entry* fgBuffer;
static entry* fgBufferUsed;
static entry* fgBufferEnd;
static entry fgInitialBuffer[64];
};
template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBuffer = fgInitialBuffer;
template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBufferUsed = fgInitialBuffer;
template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBufferEnd = &fgInitialBuffer[64];
template <typename A> typename DwarfFDECache<A>::entry DwarfFDECache<A>::fgInitialBuffer[64];
template <typename A>
pthread_rwlock_t DwarfFDECache<A>::fgLock = PTHREAD_RWLOCK_INITIALIZER;
template <typename A>
bool DwarfFDECache<A>::fgRegisteredForDyldUnloads = false;
template <typename A>
typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc)
{
pint_t result = NULL;
DEBUG_LOG_NON_ZERO(::pthread_rwlock_rdlock(&fgLock));
for(entry* p=fgBuffer; p < fgBufferUsed; ++p) {
if ( (mh == p->mh) || (mh == 0) ) {
if ( (p->ip_start <= pc) && (pc < p->ip_end) ) {
result = p->fde;
break;
}
}
}
DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
//fprintf(stderr, "DwarfFDECache::findFDE(mh=0x%llX, pc=0x%llX) => 0x%llX\n", (uint64_t)mh, (uint64_t)pc, (uint64_t)result);
return result;
}
template <typename A>
void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde)
{
//fprintf(stderr, "DwarfFDECache::add(mh=0x%llX, ip_start=0x%llX, ip_end=0x%llX, fde=0x%llX) pthread=%p\n",
// (uint64_t)mh, (uint64_t)ip_start, (uint64_t)ip_end, (uint64_t)fde, pthread_self());
DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
if ( fgBufferUsed >= fgBufferEnd ) {
int oldSize = fgBufferEnd - fgBuffer;
int newSize = oldSize*4;
entry* newBuffer = (entry*)malloc(newSize*sizeof(entry)); // can't use operator new in libSystem.dylib
memcpy(newBuffer, fgBuffer, oldSize*sizeof(entry));
//fprintf(stderr, "DwarfFDECache::add() growing buffer to %d\n", newSize);
if ( fgBuffer != fgInitialBuffer )
free(fgBuffer);
fgBuffer = newBuffer;
fgBufferUsed = &newBuffer[oldSize];
fgBufferEnd = &newBuffer[newSize];
}
fgBufferUsed->mh = mh;
fgBufferUsed->ip_start = ip_start;
fgBufferUsed->ip_end = ip_end;
fgBufferUsed->fde = fde;
++fgBufferUsed;
if ( !fgRegisteredForDyldUnloads ) {
_dyld_register_func_for_remove_image(&dyldUnloadHook);
fgRegisteredForDyldUnloads = true;
}
DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
}
template <typename A>
void DwarfFDECache<A>::removeAllIn(pint_t mh)
{
DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
entry* d=fgBuffer;
for(const entry* s=fgBuffer; s < fgBufferUsed; ++s) {
if ( s->mh != mh ) {
if ( d != s )
*d = *s;
++d;
}
}
fgBufferUsed = d;
DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
}
template <typename A>
void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide)
{
removeAllIn((pint_t)mh);
}
template <typename A>
void DwarfFDECache<A>::iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh))
{
DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock));
for(entry* p=fgBuffer; p < fgBufferUsed; ++p) {
(*func)(p->ip_start, p->ip_end, p->fde, p->mh);
}
DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock));
}
#endif // !FOR_DYLD
#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field))
template <typename A>
class UnwindSectionHeader {
public:
UnwindSectionHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
uint32_t version() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, version)); }
uint32_t commonEncodingsArraySectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArraySectionOffset)); }
uint32_t commonEncodingsArrayCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArrayCount)); }
uint32_t personalityArraySectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArraySectionOffset)); }
uint32_t personalityArrayCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArrayCount)); }
uint32_t indexSectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexSectionOffset)); }
uint32_t indexCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexCount)); }
private:
A& fAddressSpace;
typename A::pint_t fAddr;
};
template <typename A>
class UnwindSectionIndexArray {
public:
UnwindSectionIndexArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, functionOffset)); }
uint32_t secondLevelPagesSectionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, secondLevelPagesSectionOffset)); }
uint32_t lsdaIndexArraySectionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, lsdaIndexArraySectionOffset)); }
private:
A& fAddressSpace;
typename A::pint_t fAddr;
};
template <typename A>
class UnwindSectionRegularPageHeader {
public:
UnwindSectionRegularPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
uint32_t kind() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_regular_second_level_page_header, kind)); }
uint16_t entryPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryPageOffset)); }
uint16_t entryCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryCount)); }
private:
A& fAddressSpace;
typename A::pint_t fAddr;
};
template <typename A>
class UnwindSectionRegularArray {
public:
UnwindSectionRegularArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, functionOffset)); }
uint32_t encoding(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); }
private:
A& fAddressSpace;
typename A::pint_t fAddr;
};
template <typename A>
class UnwindSectionCompressedPageHeader {
public:
UnwindSectionCompressedPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
uint32_t kind() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_compressed_second_level_page_header, kind)); }
uint16_t entryPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryPageOffset)); }
uint16_t entryCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryCount)); }
uint16_t encodingsPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsPageOffset)); }
uint16_t encodingsCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsCount)); }
private:
A& fAddressSpace;
typename A::pint_t fAddr;
};
template <typename A>
class UnwindSectionCompressedArray {
public:
UnwindSectionCompressedArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
uint32_t functionOffset(int index) const INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); }
uint16_t encodingIndex(int index) const INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); }
private:
A& fAddressSpace;
typename A::pint_t fAddr;
};
template <typename A>
class UnwindSectionLsdaArray {
public:
UnwindSectionLsdaArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {}
uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, functionOffset)); }
int32_t lsdaOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, lsdaOffset)); }
private:
A& fAddressSpace;
typename A::pint_t fAddr;
};
template <typename A, typename R>
class UnwindCursor
{
public:
UnwindCursor(unw_context_t* context, A& as);
UnwindCursor(A& as, thread_t thread);
virtual ~UnwindCursor() {}
virtual bool validReg(int);
virtual uint64_t getReg(int);
virtual void setReg(int, uint64_t);
virtual bool validFloatReg(int);
virtual double getFloatReg(int);
virtual void setFloatReg(int, double);
virtual int step();
virtual void getInfo(unw_proc_info_t*);
virtual void jumpto();
virtual const char* getRegisterName(int num);
virtual bool isSignalFrame();
virtual bool getFunctionName(char* buf, size_t bufLen, unw_word_t* offset);
virtual void setInfoBasedOnIPRegister(bool isReturnAddress=false);
void operator delete(void* p, size_t size) {}
private:
typedef typename A::pint_t pint_t;
typedef uint32_t EncodedUnwindInfo;
bool getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart);
bool getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE);
int stepWithDwarfFDE()
{ return DwarfInstructions<A,R>::stepWithDwarf(fAddressSpace, this->getReg(UNW_REG_IP), fInfo.unwind_info, fRegisters); }
int stepWithCompactEncoding() { R dummy; return stepWithCompactEncoding(dummy); }
int stepWithCompactEncoding(Registers_x86_64&)
{ return CompactUnwinder_x86_64<A>::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); }
int stepWithCompactEncoding(Registers_x86&)
{ return CompactUnwinder_x86<A>::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); }
int stepWithCompactEncoding(Registers_ppc&)
{ return UNW_EINVAL; }
#if FOR_DYLD
#if __ppc__
bool mustUseDwarf() const { return true; }
#else
bool mustUseDwarf() const { return false; }
#endif
#else
bool mustUseDwarf() const { R dummy; uint32_t offset; return dwarfWithOffset(dummy, offset); }
#endif
bool dwarfWithOffset(uint32_t& offset) const { R dummy; return dwarfWithOffset(dummy, offset); }
bool dwarfWithOffset(Registers_x86_64&, uint32_t& offset) const {
if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
offset = (fInfo.format & UNWIND_X86_64_DWARF_SECTION_OFFSET);
return true;
}
#if SUPPORT_OLD_BINARIES
if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_COMPATIBILITY ) {
if ( (fInfo.format & UNWIND_X86_64_CASE_MASK) == UNWIND_X86_64_UNWIND_REQUIRES_DWARF ) {
offset = 0;
return true;
}
}
#endif
return false;
}
bool dwarfWithOffset(Registers_x86&, uint32_t& offset) const {
if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
offset = (fInfo.format & UNWIND_X86_DWARF_SECTION_OFFSET);
return true;
}
#if SUPPORT_OLD_BINARIES
if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_COMPATIBILITY ) {
if ( (fInfo.format & UNWIND_X86_CASE_MASK) == UNWIND_X86_UNWIND_REQUIRES_DWARF ) {
offset = 0;
return true;
}
}
#endif
return false;
}
bool dwarfWithOffset(Registers_ppc&, uint32_t& offset) const { return true; }
compact_unwind_encoding_t dwarfEncoding() const { R dummy; return dwarfEncoding(dummy); }
compact_unwind_encoding_t dwarfEncoding(Registers_x86_64&) const { return UNWIND_X86_64_MODE_DWARF; }
compact_unwind_encoding_t dwarfEncoding(Registers_x86&) const { return UNWIND_X86_MODE_DWARF; }
compact_unwind_encoding_t dwarfEncoding(Registers_ppc&) const { return 0; }
unw_proc_info_t fInfo;
R fRegisters;
A& fAddressSpace;
bool fUnwindInfoMissing;
bool fIsSignalFrame;
};
typedef UnwindCursor<LocalAddressSpace,Registers_x86> AbstractUnwindCursor;
template <typename A, typename R>
UnwindCursor<A,R>::UnwindCursor(unw_context_t* context, A& as)
: fRegisters(context), fAddressSpace(as), fUnwindInfoMissing(false), fIsSignalFrame(false)
{
COMPILE_TIME_ASSERT( sizeof(UnwindCursor<A,R>) < sizeof(unw_cursor_t) );
bzero(&fInfo, sizeof(fInfo));
}
template <typename A, typename R>
UnwindCursor<A,R>::UnwindCursor(A& as, thread_t thread)
: fAddressSpace(as), fUnwindInfoMissing(false), fIsSignalFrame(false)
{
bzero(&fInfo, sizeof(fInfo));
// FIXME
// fill in fRegisters from thread
}
template <typename A, typename R>
bool UnwindCursor<A,R>::validReg(int regNum)
{
return fRegisters.validRegister(regNum);
}
template <typename A, typename R>
uint64_t UnwindCursor<A,R>::getReg(int regNum)
{
return fRegisters.getRegister(regNum);
}
template <typename A, typename R>
void UnwindCursor<A,R>::setReg(int regNum, uint64_t value)
{
fRegisters.setRegister(regNum, value);
}
template <typename A, typename R>
bool UnwindCursor<A,R>::validFloatReg(int regNum)
{
return fRegisters.validFloatRegister(regNum);
}
template <typename A, typename R>
double UnwindCursor<A,R>::getFloatReg(int regNum)
{
return fRegisters.getFloatRegister(regNum);
}
template <typename A, typename R>
void UnwindCursor<A,R>::setFloatReg(int regNum, double value)
{
fRegisters.setFloatRegister(regNum, value);
}
template <typename A, typename R>
void UnwindCursor<A,R>::jumpto()
{
fRegisters.jumpto();
}
template <typename A, typename R>
const char* UnwindCursor<A,R>::getRegisterName(int regNum)
{
return fRegisters.getRegisterName(regNum);
}
template <typename A, typename R>
bool UnwindCursor<A,R>::isSignalFrame()
{
return fIsSignalFrame;
}
template <typename A, typename R>
bool UnwindCursor<A,R>::getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE)
{
typename CFI_Parser<A>::FDE_Info fdeInfo;
typename CFI_Parser<A>::CIE_Info cieInfo;
bool foundFDE = false;
bool foundInCache = false;
// if compact encoding table gave offset into dwarf section, go directly there
if ( sectionOffsetOfFDE != 0 ) {
foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, ehSectionStart+sectionOffsetOfFDE, &fdeInfo, &cieInfo);
}
#if !FOR_DYLD
if ( !foundFDE ) {
// otherwise, search cache of previously found FDEs
pint_t cachedFDE = DwarfFDECache<A>::findFDE(mh, pc);
//fprintf(stderr, "getInfoFromDwarfSection(pc=0x%llX) cachedFDE=0x%llX\n", (uint64_t)pc, (uint64_t)cachedFDE);
if ( cachedFDE != 0 ) {
foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, cachedFDE, &fdeInfo, &cieInfo);
foundInCache = foundFDE;
//fprintf(stderr, "cachedFDE=0x%llX, foundInCache=%d\n", (uint64_t)cachedFDE, foundInCache);
}
}
#endif
if ( !foundFDE ) {
// still not found, do full scan of __eh_frame section
foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, 0, &fdeInfo, &cieInfo);
}
if ( foundFDE ) {
typename CFI_Parser<A>::PrologInfo prolog;
if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
// save off parsed FDE info
fInfo.start_ip = fdeInfo.pcStart;
fInfo.end_ip = fdeInfo.pcEnd;
fInfo.lsda = fdeInfo.lsda;
fInfo.handler = cieInfo.personality;
fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function
fInfo.flags = 0;
fInfo.format = dwarfEncoding();
fInfo.unwind_info = fdeInfo.fdeStart;
fInfo.unwind_info_size = fdeInfo.fdeLength;
fInfo.extra = (unw_word_t)mh;
if ( !foundInCache && (sectionOffsetOfFDE == 0) ) {
// don't add to cache entries the compact encoding table can find quickly
//fprintf(stderr, "getInfoFromDwarfSection(pc=0x%0llX), mh=0x%llX, start_ip=0x%0llX, fde=0x%0llX, personality=0x%0llX\n",
// (uint64_t)pc, (uint64_t)mh, fInfo.start_ip, fInfo.unwind_info, fInfo.handler);
#if !FOR_DYLD
DwarfFDECache<A>::add(mh, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart);
#endif
}
return true;
}
}
//DEBUG_MESSAGE("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc);
return false;
}
template <typename A, typename R>
bool UnwindCursor<A,R>::getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart)
{
const bool log = false;
if ( log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", (uint64_t)pc, (uint64_t)mh);
const UnwindSectionHeader<A> sectionHeader(fAddressSpace, unwindSectionStart);
if ( sectionHeader.version() != UNWIND_SECTION_VERSION )
return false;
// do a binary search of top level index to find page with unwind info
uint32_t targetFunctionOffset = pc - mh;
const UnwindSectionIndexArray<A> topIndex(fAddressSpace, unwindSectionStart + sectionHeader.indexSectionOffset());
uint32_t low = 0;
uint32_t high = sectionHeader.indexCount();
const uint32_t last = high - 1;
while ( low < high ) {
uint32_t mid = (low + high)/2;
//if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", mid, low, high, topIndex.functionOffset(mid));
if ( topIndex.functionOffset(mid) <= targetFunctionOffset ) {
if ( (mid == last) || (topIndex.functionOffset(mid+1) > targetFunctionOffset) ) {
low = mid;
break;
}
else {
low = mid+1;
}
}
else {
high = mid;
}
}
const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low);
const uint32_t firstLevelNextPageFunctionOffset = topIndex.functionOffset(low+1);
const pint_t secondLevelAddr = unwindSectionStart+topIndex.secondLevelPagesSectionOffset(low);
const pint_t lsdaArrayStartAddr = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low);
const pint_t lsdaArrayEndAddr = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low+1);
if ( log ) fprintf(stderr, "\tfirst level search for result index=%d to secondLevelAddr=0x%llX\n",
low, (uint64_t)secondLevelAddr);
// do a binary search of second level page index
uint32_t encoding = 0;
pint_t funcStart = 0;
pint_t funcEnd = 0;
pint_t lsda = 0;
pint_t personality = 0;
uint32_t pageKind = fAddressSpace.get32(secondLevelAddr);
if ( pageKind == UNWIND_SECOND_LEVEL_REGULAR ) {
// regular page
UnwindSectionRegularPageHeader<A> pageHeader(fAddressSpace, secondLevelAddr);
UnwindSectionRegularArray<A> pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset());
// binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset
if ( log ) fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in regular page starting at secondLevelAddr=0x%llX\n",
(uint64_t)targetFunctionOffset, (uint64_t)secondLevelAddr);
uint32_t low = 0;
uint32_t high = pageHeader.entryCount();
while ( low < high ) {
uint32_t mid = (low + high)/2;
if ( pageIndex.functionOffset(mid) <= targetFunctionOffset ) {
if ( mid == (uint32_t)(pageHeader.entryCount()-1) ) {
// at end of table
low = mid;
funcEnd = firstLevelNextPageFunctionOffset + mh;
break;
}
else if ( pageIndex.functionOffset(mid+1) > targetFunctionOffset ) {
// next is too big, so we found it
low = mid;
funcEnd = pageIndex.functionOffset(low+1) + mh;
break;
}
else {
low = mid+1;
}
}
else {
high = mid;
}
}
encoding = pageIndex.encoding(low);
funcStart = pageIndex.functionOffset(low) + mh;
if ( pc < funcStart ) {
if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd);
return false;
}
if ( pc > funcEnd ) {
if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd);
return false;
}
}
else if ( pageKind == UNWIND_SECOND_LEVEL_COMPRESSED ) {
// compressed page
UnwindSectionCompressedPageHeader<A> pageHeader(fAddressSpace, secondLevelAddr);
UnwindSectionCompressedArray<A> pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset());
const uint32_t targetFunctionPageOffset = targetFunctionOffset - firstLevelFunctionOffset;
// binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset
if ( log ) fprintf(stderr, "\tbinary search of compressed page starting at secondLevelAddr=0x%llX\n", (uint64_t)secondLevelAddr);
uint32_t low = 0;
const uint32_t last = pageHeader.entryCount() - 1;
uint32_t high = pageHeader.entryCount();
while ( low < high ) {
uint32_t mid = (low + high)/2;
if ( pageIndex.functionOffset(mid) <= targetFunctionPageOffset ) {
if ( (mid == last) || (pageIndex.functionOffset(mid+1) > targetFunctionPageOffset) ) {
low = mid;
break;
}
else {
low = mid+1;
}
}
else {
high = mid;
}
}
funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset + mh;
if ( low < last )
funcEnd = pageIndex.functionOffset(low+1) + firstLevelFunctionOffset + mh;
else
funcEnd = firstLevelNextPageFunctionOffset + mh;
if ( pc < funcStart ) {
DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcStart=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart);
return false;
}
if ( pc > funcEnd ) {
DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcEnd);
return false;
}
uint16_t encodingIndex = pageIndex.encodingIndex(low);
if ( encodingIndex < sectionHeader.commonEncodingsArrayCount() ) {
// encoding is in common table in section header
encoding = fAddressSpace.get32(unwindSectionStart+sectionHeader.commonEncodingsArraySectionOffset()+encodingIndex*sizeof(uint32_t));
}
else {
// encoding is in page specific table
uint16_t pageEncodingIndex = encodingIndex-sectionHeader.commonEncodingsArrayCount();
encoding = fAddressSpace.get32(secondLevelAddr+pageHeader.encodingsPageOffset()+pageEncodingIndex*sizeof(uint32_t));
}
}
else {
DEBUG_MESSAGE("malformed __unwind_info at 0x%0llX bad second level page\n", (uint64_t)unwindSectionStart);
return false;
}
// look up LSDA, if encoding says function has one
if ( encoding & UNWIND_HAS_LSDA ) {
UnwindSectionLsdaArray<A> lsdaIndex(fAddressSpace, lsdaArrayStartAddr);
uint32_t funcStartOffset = funcStart - mh;
uint32_t low = 0;
uint32_t high = (lsdaArrayEndAddr-lsdaArrayStartAddr)/sizeof(unwind_info_section_header_lsda_index_entry);
// binary search looks for entry with exact match for functionOffset
if ( log ) fprintf(stderr, "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", funcStartOffset);
while ( low < high ) {
uint32_t mid = (low + high)/2;
if ( lsdaIndex.functionOffset(mid) == funcStartOffset ) {
lsda = lsdaIndex.lsdaOffset(mid) + mh;
break;
}
else if ( lsdaIndex.functionOffset(mid) < funcStartOffset ) {
low = mid+1;
}
else {
high = mid;
}
}
if ( lsda == 0 ) {
DEBUG_MESSAGE("found encoding 0x%08X with HAS_LSDA bit set for pc=0x%0llX, but lsda table has no entry\n", encoding, (uint64_t)pc);
return false;
}
}
// extact personality routine, if encoding says function has one
uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> (__builtin_ctz(UNWIND_PERSONALITY_MASK));
if ( personalityIndex != 0 ) {
--personalityIndex; // change 1-based to zero-based index
if ( personalityIndex > sectionHeader.personalityArrayCount() ) {
DEBUG_MESSAGE("found encoding 0x%08X with personality index %d, but personality table has only %d entires\n",
encoding, personalityIndex, sectionHeader.personalityArrayCount());
return false;
}
int32_t personalityDelta = fAddressSpace.get32(unwindSectionStart+sectionHeader.personalityArraySectionOffset()+personalityIndex*sizeof(uint32_t));
pint_t personalityPointer = personalityDelta + mh;
personality = fAddressSpace.getP(personalityPointer);
if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), personalityDelta=0x%08X, personality=0x%08llX\n",
(uint64_t)pc, personalityDelta, (uint64_t)personality);
}
if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n",
(uint64_t)pc, encoding, (uint64_t)lsda, (uint64_t)funcStart);
fInfo.start_ip = funcStart;
fInfo.end_ip = funcEnd;
fInfo.lsda = lsda;
fInfo.handler = personality;
fInfo.gp = 0;
fInfo.flags = 0;
fInfo.format = encoding;
fInfo.unwind_info = 0;
fInfo.unwind_info_size = 0;
fInfo.extra = mh;
return true;
}
template <typename A, typename R>
void UnwindCursor<A,R>::setInfoBasedOnIPRegister(bool isReturnAddress)
{
pint_t pc = this->getReg(UNW_REG_IP);
// if the last line of a function is a "throw" the compile sometimes
// emits no instructions after the call to __cxa_throw. This means
// the return address is actually the start of the next function.
// To disambiguate this, back up the pc when we know it is a return
// address.
if ( isReturnAddress )
--pc;
// ask address space object to find unwind sections for this pc
pint_t mh;
pint_t dwarfStart;
pint_t dwarfLength;
pint_t compactStart;
if ( fAddressSpace.findUnwindSections(pc, mh, dwarfStart, dwarfLength, compactStart) ) {
// if there is a compact unwind encoding table, look there first
if ( compactStart != 0 ) {
if ( this->getInfoFromCompactEncodingSection(pc, mh, compactStart) ) {
#if !FOR_DYLD
// found info in table, done unless encoding says to use dwarf
uint32_t offsetInDwarfSection;
if ( (dwarfStart != 0) && dwarfWithOffset(offsetInDwarfSection) ) {
if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, offsetInDwarfSection) ) {
// found info in dwarf, done
return;
}
}
#endif
// if unwind table has entry, but entry says there is no unwind info, note that
if ( fInfo.format == 0 )
fUnwindInfoMissing = true;
// old compact encoding
if ( !mustUseDwarf() ) {
return;
}
}
}
#if !FOR_DYLD || __ppc__
// if there is dwarf unwind info, look there next
if ( dwarfStart != 0 ) {
if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, 0) ) {
// found info in dwarf, done
return;
}
}
#endif
}
#if !FOR_DYLD
// the PC is not in code loaded by dyld, look through __register_frame() registered FDEs
pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc);
if ( cachedFDE != 0 ) {
CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
const char* msg = CFI_Parser<A>::decodeFDE(fAddressSpace, cachedFDE, &fdeInfo, &cieInfo);
if ( msg == NULL ) {
typename CFI_Parser<A>::PrologInfo prolog;
if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
// save off parsed FDE info
fInfo.start_ip = fdeInfo.pcStart;
fInfo.end_ip = fdeInfo.pcEnd;
fInfo.lsda = fdeInfo.lsda;
fInfo.handler = cieInfo.personality;
fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function
fInfo.flags = 0;
fInfo.format = dwarfEncoding();
fInfo.unwind_info = fdeInfo.fdeStart;
fInfo.unwind_info_size = fdeInfo.fdeLength;
fInfo.extra = 0;
return;
}
}
}
#if KEYMGR_SUPPPORT
// lastly check for old style keymgr registration of dynamically generated FDEs
// acquire exclusive access to libgcc_object_info
libgcc_object_info* head = (libgcc_object_info*)_keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
if ( head != NULL ) {
// look at each FDE in keymgr
for (libgcc_object* ob = head->unseen_objects; ob != NULL; ob = ob->next) {
CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
const char* msg = CFI_Parser<A>::decodeFDE(fAddressSpace, (pint_t)ob->fde, &fdeInfo, &cieInfo);
if ( msg == NULL ) {
// see if this FDE is for a function that includes the pc we are looking for
if ( (fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd) ) {
typename CFI_Parser<A>::PrologInfo prolog;
if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) {
// save off parsed FDE info
fInfo.start_ip = fdeInfo.pcStart;
fInfo.end_ip = fdeInfo.pcEnd;
fInfo.lsda = fdeInfo.lsda;
fInfo.handler = cieInfo.personality;
fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function
fInfo.flags = 0;
fInfo.format = dwarfEncoding();
fInfo.unwind_info = fdeInfo.fdeStart;
fInfo.unwind_info_size = fdeInfo.fdeLength;
fInfo.extra = 0;
_keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
return;
}
}
}
}
}
// release libgcc_object_info
_keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
#endif // KEYMGR_SUPPPORT
#endif
// no unwind info, flag that we can't reliable unwind
fUnwindInfoMissing = true;
}
template <typename A, typename R>
int UnwindCursor<A,R>::step()
{
// bottom of stack is defined as when no more unwind info
if ( fUnwindInfoMissing )
return UNW_STEP_END;
// apply unwinding to register set
int result;
if ( this->mustUseDwarf() )
result = this->stepWithDwarfFDE();
else
result = this->stepWithCompactEncoding();
// update info based on new PC
if ( result == UNW_STEP_SUCCESS ) {
this->setInfoBasedOnIPRegister(true);
if ( fUnwindInfoMissing )
return UNW_STEP_END;
}
return result;
}
template <typename A, typename R>
void UnwindCursor<A,R>::getInfo(unw_proc_info_t* info)
{
*info = fInfo;
}
template <typename A, typename R>
bool UnwindCursor<A,R>::getFunctionName(char* buf, size_t bufLen, unw_word_t* offset)
{
return fAddressSpace.findFunctionName(this->getReg(UNW_REG_IP), buf, bufLen, offset);
}
}; // namespace libunwind
#endif // __UNWINDCURSOR_HPP__

306
src/UnwindLevel1-gcc-ext.c Normal file
View File

@ -0,0 +1,306 @@
/* -*- mode: C++; c-basic-offset: 4; -*-
*
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
* Implements gcc extensions to the C++ ABI Exception Handling Level 1 as documented at:
* <http://www.codesourcery.com/cxx-abi/abi-eh.html>
* using libunwind
*
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "libunwind.h"
#include "unwind.h"
#include "libunwind_priv.h"
#include "InternalMacros.h"
#if __ppc__ || __i386__ || __x86_64__
//
// Called by __cxa_rethrow()
//
EXPORT _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n", exception_object, exception_object->private_1);
// if this is non-forced and a stopping place was found, then this is a re-throw
// call _Unwind_RaiseException() as if this was a new exception
if ( exception_object->private_1 == 0 ) {
return _Unwind_RaiseException(exception_object);
// should return if there is no catch clause, so that __cxa_rethrow can call std::terminate()
}
// call through to _Unwind_Resume() which distiguishes between forced and regular exceptions
_Unwind_Resume(exception_object);
ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException() which unexpectedly returned");
}
//
// Called by personality handler during phase 2 to get base address for data relative encodings
//
EXPORT uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context* context)
{
DEBUG_PRINT_API("_Unwind_GetDataRelBase(context=%p)\n", context);
ABORT("_Unwind_GetDataRelBase() not implemented");
}
//
// Called by personality handler during phase 2 to get base address for text relative encodings
//
EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context* context)
{
DEBUG_PRINT_API("_Unwind_GetTextRelBase(context=%p)\n", context);
ABORT("_Unwind_GetTextRelBase() not implemented");
}
//
// Scans unwind information to find the function that contains the
// specified code address "pc".
//
EXPORT void* _Unwind_FindEnclosingFunction(void* pc)
{
DEBUG_PRINT_API("_Unwind_FindEnclosingFunction(pc=%p)\n", pc);
// This is slow, but works.
// We create an unwind cursor then alter the IP to be pc
unw_cursor_t cursor;
unw_context_t uc;
unw_proc_info_t info;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long)pc);
if ( unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS )
return (void*)(long)info.start_ip;
else
return NULL;
}
//
// Walk every frame and call trace function at each one. If trace function
// returns anything other than _URC_NO_REASON, then walk is terminated.
//
EXPORT _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn callback, void* ref)
{
unw_cursor_t cursor;
unw_context_t uc;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
DEBUG_PRINT_API("_Unwind_Backtrace(callback=%p)\n", callback);
// walk each frame
while ( true ) {
// ask libuwind to get next frame (skip over first frame which is _Unwind_Backtrace())
if ( unw_step(&cursor) <= 0 ) {
DEBUG_PRINT_UNWINDING(" _backtrace: ended because cursor reached bottom of stack, returning %d\n", _URC_END_OF_STACK);
return _URC_END_OF_STACK;
}
// debugging
if ( DEBUG_PRINT_UNWINDING_TEST ) {
char functionName[512];
unw_proc_info_t frameInfo;
unw_word_t offset;
unw_get_proc_name(&cursor, functionName, 512, &offset);
unw_get_proc_info(&cursor, &frameInfo);
DEBUG_PRINT_UNWINDING(" _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p\n",
frameInfo.start_ip, functionName, frameInfo.lsda, &cursor);
}
// call trace function with this frame
_Unwind_Reason_Code result = (*callback)((struct _Unwind_Context*)(&cursor), ref);
if ( result != _URC_NO_REASON ) {
DEBUG_PRINT_UNWINDING(" _backtrace: ended because callback returned %d\n", result);
return result;
}
}
}
//
// Find dwarf unwind info for an address 'pc' in some function.
//
EXPORT const void* _Unwind_Find_FDE(const void* pc, struct dwarf_eh_bases* bases)
{
// This is slow, but works.
// We create an unwind cursor then alter the IP to be pc
unw_cursor_t cursor;
unw_context_t uc;
unw_proc_info_t info;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long)pc);
unw_get_proc_info(&cursor, &info);
bases->tbase = info.extra;
bases->dbase = 0; // dbase not used on Mac OS X
bases->func = info.start_ip;
DEBUG_PRINT_API("_Unwind_Find_FDE(pc=%p) => %p\n", pc, (void*)(long)info.unwind_info);
return (void*)(long)info.unwind_info;
}
EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context* context)
{
unw_cursor_t* cursor = (unw_cursor_t*)context;
unw_word_t result;
unw_get_reg(cursor, UNW_REG_SP, &result);
DEBUG_PRINT_API("_Unwind_GetCFA(context=%p) => 0x%llX\n", context, (uint64_t)result);
return result;
}
//
// Called by personality handler during phase 2 to get instruction pointer.
// ipBefore is a boolean that says if IP is already adjusted to be the call
// site address. Normally IP is the return address.
//
EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context* context, int* ipBefore)
{
DEBUG_PRINT_API("_Unwind_GetIPInfo(context=%p)\n", context);
*ipBefore = 0;
return _Unwind_GetIP(context);
}
//
// Called by programs with dynamic code generators that want
// to register a dynamically generated FDE.
// This function has existed on Mac OS X since 10.4, but
// never worked before.
//
EXPORT void __register_frame(const void* fde)
{
DEBUG_PRINT_API("__register_frame(%p)\n", fde);
_unw_add_dynamic_fde((unw_word_t)(uintptr_t)fde);
}
//
// Called by programs with dynamic code generators that want
// to unregister a dynamically generated FDE.
// This function has existed on Mac OS X since 10.4, but
// never worked before.
//
EXPORT void __deregister_frame(const void* fde)
{
DEBUG_PRINT_API("__deregister_frame(%p)\n", fde);
_unw_remove_dynamic_fde((unw_word_t)(uintptr_t)fde);
}
//
// The following register/deregister functions are gcc extensions.
// They have existed on Mac OS X, but have never worked because Mac OS X
// before 10.6 used keymgr to track known FDEs, but these functions
// never got updated to use keymgr.
// For now, we implement these as do-nothing functions to keep any existing
// applications working. We also add the not in 10.6 symbol so that nwe
// application won't be able to use them.
//
EXPORT void __register_frame_info_bases(const void* fde, void* ob, void* tb, void* db)
{
DEBUG_PRINT_API("__register_frame_info_bases(%p,%p, %p, %p)\n", fde, ob, tb, db);
// do nothing, this function never worked in Mac OS X
}
EXPORT void __register_frame_info(const void* fde, void* ob)
{
DEBUG_PRINT_API("__register_frame_info(%p, %p)\n", fde, ob);
// do nothing, this function never worked in Mac OS X
}
EXPORT void __register_frame_info_table_bases(const void* fde, void* ob, void* tb, void* db)
{
DEBUG_PRINT_API("__register_frame_info_table_bases(%p,%p, %p, %p)\n", fde, ob, tb, db);
// do nothing, this function never worked in Mac OS X
}
EXPORT void __register_frame_info_table(const void* fde, void* ob)
{
DEBUG_PRINT_API("__register_frame_info_table(%p, %p)\n", fde, ob);
// do nothing, this function never worked in Mac OS X
}
EXPORT void __register_frame_table(const void* fde)
{
DEBUG_PRINT_API("__register_frame_table(%p)\n", fde);
// do nothing, this function never worked in Mac OS X
}
EXPORT void* __deregister_frame_info(const void* fde)
{
DEBUG_PRINT_API("__deregister_frame_info(%p)\n", fde);
// do nothing, this function never worked in Mac OS X
return NULL;
}
EXPORT void* __deregister_frame_info_bases(const void* fde)
{
DEBUG_PRINT_API("__deregister_frame_info_bases(%p)\n", fde);
// do nothing, this function never worked in Mac OS X
return NULL;
}
//
// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in earlier versions
//
NOT_HERE_BEFORE_10_6(_Unwind_Backtrace)
NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction)
NOT_HERE_BEFORE_10_6(_Unwind_GetCFA)
NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase)
NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase)
NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow)
NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo)
NOT_HERE_BEFORE_10_6(__register_frame)
NOT_HERE_BEFORE_10_6(__deregister_frame)
//
// symbols in libSystem.dylib for compatibility, but we don't want any new code using them
//
NEVER_HERE(__register_frame_info_bases)
NEVER_HERE(__register_frame_info)
NEVER_HERE(__register_frame_info_table_bases)
NEVER_HERE(__register_frame_info_table)
NEVER_HERE(__register_frame_table)
NEVER_HERE(__deregister_frame_info)
NEVER_HERE(__deregister_frame_info_bases)
#endif // __ppc__ || __i386__ || __x86_64__

455
src/UnwindLevel1.c Normal file
View File

@ -0,0 +1,455 @@
/* -*- mode: C++; c-basic-offset: 4; -*-
*
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*
* Implements C++ ABI Exception Handling Level 1 as documented at:
* <http://www.codesourcery.com/cxx-abi/abi-eh.html>
* using libunwind
*
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "libunwind.h"
#include "unwind.h"
#include "InternalMacros.h"
#if __ppc__ || __i386__ || __x86_64__
static _Unwind_Reason_Code unwind_phase1(unw_context_t* uc, struct _Unwind_Exception* exception_object)
{
unw_cursor_t cursor1;
unw_init_local(&cursor1, uc);
// walk each frame looking for a place to stop
for (bool handlerNotFound = true; handlerNotFound; ) {
// ask libuwind to get next frame (skip over first which is _Unwind_RaiseException)
int stepResult = unw_step(&cursor1);
if ( stepResult == 0 ) {
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
return _URC_END_OF_STACK;
}
else if ( stepResult < 0 ) {
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
return _URC_FATAL_PHASE1_ERROR;
}
// see if frame has code to run (has personality routine)
unw_proc_info_t frameInfo;
unw_word_t sp;
if ( unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS ) {
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
return _URC_FATAL_PHASE1_ERROR;
}
// debugging
if ( DEBUG_PRINT_UNWINDING_TEST ) {
char functionName[512];
unw_word_t offset;
if ( (unw_get_proc_name(&cursor1, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
strcpy(functionName, ".anonymous.");
unw_word_t pc;
unw_get_reg(&cursor1, UNW_REG_IP, &pc);
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, lsda=0x%llX, personality=0x%llX\n",
exception_object, pc, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler);
}
// if there is a personality routine, ask it if it will want to stop at this frame
if ( frameInfo.handler != 0 ) {
__personality_routine p = (__personality_routine)(long)(frameInfo.handler);
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): calling personality function %p\n", exception_object, p);
_Unwind_Reason_Code personalityResult = (*p)(1, _UA_SEARCH_PHASE,
exception_object->exception_class, exception_object,
(struct _Unwind_Context*)(&cursor1));
switch ( personalityResult ) {
case _URC_HANDLER_FOUND:
// found a catch clause or locals that need destructing in this frame
// stop search and remember stack pointer at the frame
handlerNotFound = false;
unw_get_reg(&cursor1, UNW_REG_SP, &sp);
exception_object->private_2 = sp;
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND\n", exception_object);
return _URC_NO_REASON;
case _URC_CONTINUE_UNWIND:
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
// continue unwinding
break;
default:
// something went wrong
DEBUG_PRINT_UNWINDING("unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", exception_object);
return _URC_FATAL_PHASE1_ERROR;
}
}
}
return _URC_NO_REASON;
}
static _Unwind_Reason_Code unwind_phase2(unw_context_t* uc, struct _Unwind_Exception* exception_object)
{
unw_cursor_t cursor2;
unw_init_local(&cursor2, uc);
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
// walk each frame until we reach where search phase said to stop
while ( true ) {
// ask libuwind to get next frame (skip over first which is _Unwind_RaiseException)
int stepResult = unw_step(&cursor2);
if ( stepResult == 0 ) {
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached bottom => _URC_END_OF_STACK\n", exception_object);
return _URC_END_OF_STACK;
}
else if ( stepResult < 0 ) {
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
return _URC_FATAL_PHASE2_ERROR;
}
// get info about this frame
unw_word_t sp;
unw_proc_info_t frameInfo;
unw_get_reg(&cursor2, UNW_REG_SP, &sp);
if ( unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS ) {
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info failed => _URC_FATAL_PHASE1_ERROR\n", exception_object);
return _URC_FATAL_PHASE2_ERROR;
}
// debugging
if ( DEBUG_PRINT_UNWINDING_TEST ) {
char functionName[512];
unw_word_t offset;
if ( (unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
strcpy(functionName, ".anonymous.");
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, lsda=0x%llX, personality=0x%llX\n",
exception_object, frameInfo.start_ip, functionName, sp, frameInfo.lsda, frameInfo.handler);
}
// if there is a personality routine, tell it we are unwinding
if ( frameInfo.handler != 0 ) {
__personality_routine p = (__personality_routine)(long)(frameInfo.handler);
_Unwind_Action action = _UA_CLEANUP_PHASE;
if ( sp == exception_object->private_2 )
action = (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME); // tell personality this was the frame it marked in phase 1
_Unwind_Reason_Code personalityResult = (*p)(1, action,
exception_object->exception_class, exception_object,
(struct _Unwind_Context*)(&cursor2));
switch ( personalityResult ) {
case _URC_CONTINUE_UNWIND:
// continue unwinding
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object);
if ( sp == exception_object->private_2 ) {
// phase 1 said we would stop at this frame, but we did not...
ABORT("during phase1 personality function said it would stop here, but now if phase2 it did not stop here");
}
break;
case _URC_INSTALL_CONTEXT:
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", exception_object);
// personality routine says to transfer control to landing pad
// we may get control back if landing pad calls _Unwind_Resume()
if ( DEBUG_PRINT_UNWINDING_TEST ) {
unw_word_t pc;
unw_word_t sp;
unw_get_reg(&cursor2, UNW_REG_IP, &pc);
unw_get_reg(&cursor2, UNW_REG_SP, &sp);
DEBUG_PRINT_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering user code with ip=0x%llX, sp=0x%llX\n", exception_object, pc, sp);
}
unw_resume(&cursor2);
// unw_resume() only returns if there was an error
return _URC_FATAL_PHASE2_ERROR;
default:
// something went wrong
DEBUG_MESSAGE("personality function returned unknown result %d", personalityResult);
return _URC_FATAL_PHASE2_ERROR;
}
}
}
// clean up phase did not resume at the frame that the search phase said it would
return _URC_FATAL_PHASE2_ERROR;
}
static _Unwind_Reason_Code unwind_phase2_forced(unw_context_t* uc, struct _Unwind_Exception* exception_object,
_Unwind_Stop_Fn stop, void* stop_parameter)
{
unw_cursor_t cursor2;
unw_init_local(&cursor2, uc);
// walk each frame until we reach where search phase said to stop
while ( unw_step(&cursor2) > 0 ) {
// get info about this frame
unw_proc_info_t frameInfo;
if ( unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS ) {
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step failed => _URC_END_OF_STACK\n", exception_object);
return _URC_FATAL_PHASE1_ERROR;
}
// debugging
if ( DEBUG_PRINT_UNWINDING_TEST ) {
char functionName[512];
unw_word_t offset;
if ( (unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip+offset > frameInfo.end_ip) )
strcpy(functionName, ".anonymous.");
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): start_ip=0x%llX, func=%s, lsda=0x%llX, personality=0x%llX\n",
exception_object, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler);
}
// call stop function at each frame
_Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE);
_Unwind_Reason_Code stopResult = (*stop)(1, action,
exception_object->exception_class, exception_object,
(struct _Unwind_Context*)(&cursor2), stop_parameter);
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult);
if ( stopResult != _URC_NO_REASON ) {
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object);
return _URC_FATAL_PHASE2_ERROR;
}
// if there is a personality routine, tell it we are unwinding
if ( frameInfo.handler != 0 ) {
__personality_routine p = (__personality_routine)(long)(frameInfo.handler);
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p);
_Unwind_Reason_Code personalityResult = (*p)(1, action,
exception_object->exception_class, exception_object,
(struct _Unwind_Context*)(&cursor2));
switch ( personalityResult ) {
case _URC_CONTINUE_UNWIND:
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_CONTINUE_UNWIND\n", exception_object);
// destructors called, continue unwinding
break;
case _URC_INSTALL_CONTEXT:
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned _URC_INSTALL_CONTEXT\n", exception_object);
// we may get control back if landing pad calls _Unwind_Resume()
unw_resume(&cursor2);
break;
default:
// something went wrong
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): personality returned %d, _URC_FATAL_PHASE2_ERROR\n",
exception_object, personalityResult);
return _URC_FATAL_PHASE2_ERROR;
}
}
}
// call stop function one last time and tell it we've reached the end of the stack
DEBUG_PRINT_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop function with _UA_END_OF_STACK\n", exception_object);
_Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND|_UA_CLEANUP_PHASE|_UA_END_OF_STACK);
(*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context*)(&cursor2), stop_parameter);
// clean up phase did not resume at the frame that the search phase said it would
return _URC_FATAL_PHASE2_ERROR;
}
//
// Called by __cxa_throw. Only returns if there is a fatal error
//
EXPORT _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_API("_Unwind_RaiseException(ex_obj=%p)\n", exception_object);
unw_context_t uc;
unw_getcontext(&uc);
// mark that this is a non-forced unwind, so _Unwind_Resume() can do the right thing
exception_object->private_1 = 0;
exception_object->private_2 = 0;
// phase 1: the search phase
_Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object);
if ( phase1 != _URC_NO_REASON )
return phase1;
// phase 2: the clean up phase
return unwind_phase2(&uc, exception_object);
}
//
// When _Unwind_RaiseException() is in phase2, it hands control
// to the personality function at each frame. The personality
// may force a jump to a landing pad in that function, the landing
// pad code may then call _Unwind_Resume() to continue with the
// unwinding. Note: the call to _Unwind_Resume() is from compiler
// geneated user code. All other _Unwind_* routines are called
// by the C++ runtime __cxa_* routines.
//
// Re-throwing an exception is implemented by having the code call
// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
//
EXPORT void _Unwind_Resume(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_API("_Unwind_Resume(ex_obj=%p)\n", exception_object);
unw_context_t uc;
unw_getcontext(&uc);
if ( exception_object->private_1 != 0 )
unwind_phase2_forced(&uc, exception_object, (_Unwind_Stop_Fn)exception_object->private_1, (void*)exception_object->private_2);
else
unwind_phase2(&uc, exception_object);
// clients assume _Unwind_Resume() does not return, so all we can do is abort.
ABORT("_Unwind_Resume() can't return");
}
//
// Not used by C++.
// Unwinds stack, calling "stop" function at each frame
// Could be used to implement longjmp().
//
EXPORT _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception* exception_object, _Unwind_Stop_Fn stop, void* stop_parameter)
{
DEBUG_PRINT_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)\n", exception_object, stop);
unw_context_t uc;
unw_getcontext(&uc);
// mark that this is a forced unwind, so _Unwind_Resume() can do the right thing
exception_object->private_1 = (uintptr_t)stop;
exception_object->private_2 = (uintptr_t)stop_parameter;
// doit
return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter);
}
//
// Called by personality handler during phase 2 to get LSDA for current frame
//
EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context)
{
unw_cursor_t* cursor = (unw_cursor_t*)context;
unw_proc_info_t frameInfo;
uintptr_t result = 0;
if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS )
result = frameInfo.lsda;
DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lX\n", context, result);
if ( result != 0 ) {
if ( *((uint8_t*)result) != 0xFF )
DEBUG_MESSAGE("lsda at 0x%lX does not start with 0xFF\n", result);
}
return result;
}
//
// Called by personality handler during phase 2 to get register values
//
EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, int index)
{
unw_cursor_t* cursor = (unw_cursor_t*)context;
unw_word_t result;
unw_get_reg(cursor, index, &result);
DEBUG_PRINT_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%llX\n", context, index, (uint64_t)result);
return result;
}
//
// Called by personality handler during phase 2 to alter register values
//
EXPORT void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value)
{
DEBUG_PRINT_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0llX)\n", context, index, (uint64_t)new_value);
unw_cursor_t* cursor = (unw_cursor_t*)context;
unw_set_reg(cursor, index, new_value);
}
//
// Called by personality handler during phase 2 to get instruction pointer
//
EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context* context)
{
unw_cursor_t* cursor = (unw_cursor_t*)context;
unw_word_t result;
unw_get_reg(cursor, UNW_REG_IP, &result);
DEBUG_PRINT_API("_Unwind_GetIP(context=%p) => 0x%llX\n", context, (uint64_t)result);
return result;
}
//
// Called by personality handler during phase 2 to alter instruction pointer
//
EXPORT void _Unwind_SetIP(struct _Unwind_Context* context, uintptr_t new_value)
{
DEBUG_PRINT_API("_Unwind_SetIP(context=%p, value=0x%0llX)\n", context, (uint64_t)new_value);
unw_cursor_t* cursor = (unw_cursor_t*)context;
unw_set_reg(cursor, UNW_REG_IP, new_value);
}
//
// Called by personality handler during phase 2 to find the start of the function
//
EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context)
{
unw_cursor_t* cursor = (unw_cursor_t*)context;
unw_proc_info_t frameInfo;
uintptr_t result = 0;
if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS )
result = frameInfo.start_ip;
DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p) => 0x%lX\n", context, result);
return result;
}
//
// Called by personality handler during phase 2 if a foreign exception is caught
//
EXPORT void _Unwind_DeleteException(struct _Unwind_Exception* exception_object)
{
DEBUG_PRINT_API("_Unwind_DeleteException(ex_obj=%p)\n", exception_object);
if ( exception_object->exception_cleanup != NULL )
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exception_object);
}
//
// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in earlier versions
//
NOT_HERE_BEFORE_10_6(_Unwind_DeleteException)
NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE)
NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind)
NOT_HERE_BEFORE_10_6(_Unwind_GetGR)
NOT_HERE_BEFORE_10_6(_Unwind_GetIP)
NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData)
NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart)
NOT_HERE_BEFORE_10_6(_Unwind_RaiseException)
NOT_HERE_BEFORE_10_6(_Unwind_Resume)
NOT_HERE_BEFORE_10_6(_Unwind_SetGR)
NOT_HERE_BEFORE_10_6(_Unwind_SetIP)
#endif // __ppc__ || __i386__ || __x86_64__

255
src/dwarf2.h Normal file
View File

@ -0,0 +1,255 @@
/*
* Copyright (c) 2007-2008 Apple, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/* These constants were taken from version 3 of the DWARF standard,
which is Copyright (c) 2005 Free Standards Group, and
Copyright (c) 1992, 1993 UNIX International, Inc.
*/
#ifndef __DWARF2__
#define __DWARF2__
// dwarf unwind instructions
enum {
DW_CFA_nop = 0x0,
DW_CFA_set_loc = 0x1,
DW_CFA_advance_loc1 = 0x2,
DW_CFA_advance_loc2 = 0x3,
DW_CFA_advance_loc4 = 0x4,
DW_CFA_offset_extended = 0x5,
DW_CFA_restore_extended = 0x6,
DW_CFA_undefined = 0x7,
DW_CFA_same_value = 0x8,
DW_CFA_register = 0x9,
DW_CFA_remember_state = 0xA,
DW_CFA_restore_state = 0xB,
DW_CFA_def_cfa = 0xC,
DW_CFA_def_cfa_register = 0xD,
DW_CFA_def_cfa_offset = 0xE,
DW_CFA_def_cfa_expression = 0xF,
DW_CFA_expression = 0x10,
DW_CFA_offset_extended_sf = 0x11,
DW_CFA_def_cfa_sf = 0x12,
DW_CFA_def_cfa_offset_sf = 0x13,
DW_CFA_val_offset = 0x14,
DW_CFA_val_offset_sf = 0x15,
DW_CFA_val_expression = 0x16,
DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register
DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
// GNU extensions
DW_CFA_GNU_window_save = 0x2D,
DW_CFA_GNU_args_size = 0x2E,
DW_CFA_GNU_negative_offset_extended = 0x2F
};
// FSF exception handling Pointer-Encoding constants
// Used in CFI augmentation by gcc compiler
enum {
DW_EH_PE_ptr = 0x00,
DW_EH_PE_uleb128 = 0x01,
DW_EH_PE_udata2 = 0x02,
DW_EH_PE_udata4 = 0x03,
DW_EH_PE_udata8 = 0x04,
DW_EH_PE_signed = 0x08,
DW_EH_PE_sleb128 = 0x09,
DW_EH_PE_sdata2 = 0x0A,
DW_EH_PE_sdata4 = 0x0B,
DW_EH_PE_sdata8 = 0x0C,
DW_EH_PE_absptr = 0x00,
DW_EH_PE_pcrel = 0x10,
DW_EH_PE_textrel = 0x20,
DW_EH_PE_datarel = 0x30,
DW_EH_PE_funcrel = 0x40,
DW_EH_PE_aligned = 0x50,
DW_EH_PE_indirect = 0x80,
DW_EH_PE_omit = 0xFF
};
// DWARF expressions
enum {
DW_OP_addr = 0x03, // constant address (size target specific)
DW_OP_deref = 0x06,
DW_OP_const1u = 0x08, // 1-byte constant
DW_OP_const1s = 0x09, // 1-byte constant
DW_OP_const2u = 0x0A, // 2-byte constant
DW_OP_const2s = 0x0B, // 2-byte constant
DW_OP_const4u = 0x0C, // 4-byte constant
DW_OP_const4s = 0x0D, // 4-byte constant
DW_OP_const8u = 0x0E, // 8-byte constant
DW_OP_const8s = 0x0F, // 8-byte constant
DW_OP_constu = 0x10, // ULEB128 constant
DW_OP_consts = 0x11, // SLEB128 constant
DW_OP_dup = 0x12,
DW_OP_drop = 0x13,
DW_OP_over = 0x14,
DW_OP_pick = 0x15, // 1-byte stack index
DW_OP_swap = 0x16,
DW_OP_rot = 0x17,
DW_OP_xderef = 0x18,
DW_OP_abs = 0x19,
DW_OP_and = 0x1A,
DW_OP_div = 0x1B,
DW_OP_minus = 0x1C,
DW_OP_mod = 0x1D,
DW_OP_mul = 0x1E,
DW_OP_neg = 0x1F,
DW_OP_not = 0x20,
DW_OP_or = 0x21,
DW_OP_plus = 0x22,
DW_OP_plus_uconst = 0x23, // ULEB128 addend
DW_OP_shl = 0x24,
DW_OP_shr = 0x25,
DW_OP_shra = 0x26,
DW_OP_xor = 0x27,
DW_OP_skip = 0x2F, // signed 2-byte constant
DW_OP_bra = 0x28, // signed 2-byte constant
DW_OP_eq = 0x29,
DW_OP_ge = 0x2A,
DW_OP_gt = 0x2B,
DW_OP_le = 0x2C,
DW_OP_lt = 0x2D,
DW_OP_ne = 0x2E,
DW_OP_lit0 = 0x30, // Literal 0
DW_OP_lit1 = 0x31, // Literal 1
DW_OP_lit2 = 0x32, // Literal 2
DW_OP_lit3 = 0x33, // Literal 3
DW_OP_lit4 = 0x34, // Literal 4
DW_OP_lit5 = 0x35, // Literal 5
DW_OP_lit6 = 0x36, // Literal 6
DW_OP_lit7 = 0x37, // Literal 7
DW_OP_lit8 = 0x38, // Literal 8
DW_OP_lit9 = 0x39, // Literal 9
DW_OP_lit10 = 0x3A, // Literal 10
DW_OP_lit11 = 0x3B, // Literal 11
DW_OP_lit12 = 0x3C, // Literal 12
DW_OP_lit13 = 0x3D, // Literal 13
DW_OP_lit14 = 0x3E, // Literal 14
DW_OP_lit15 = 0x3F, // Literal 15
DW_OP_lit16 = 0x40, // Literal 16
DW_OP_lit17 = 0x41, // Literal 17
DW_OP_lit18 = 0x42, // Literal 18
DW_OP_lit19 = 0x43, // Literal 19
DW_OP_lit20 = 0x44, // Literal 20
DW_OP_lit21 = 0x45, // Literal 21
DW_OP_lit22 = 0x46, // Literal 22
DW_OP_lit23 = 0x47, // Literal 23
DW_OP_lit24 = 0x48, // Literal 24
DW_OP_lit25 = 0x49, // Literal 25
DW_OP_lit26 = 0x4A, // Literal 26
DW_OP_lit27 = 0x4B, // Literal 27
DW_OP_lit28 = 0x4C, // Literal 28
DW_OP_lit29 = 0x4D, // Literal 29
DW_OP_lit30 = 0x4E, // Literal 30
DW_OP_lit31 = 0x4F, // Literal 31
DW_OP_reg0 = 0x50, // Contents of reg0
DW_OP_reg1 = 0x51, // Contents of reg1
DW_OP_reg2 = 0x52, // Contents of reg2
DW_OP_reg3 = 0x53, // Contents of reg3
DW_OP_reg4 = 0x54, // Contents of reg4
DW_OP_reg5 = 0x55, // Contents of reg5
DW_OP_reg6 = 0x56, // Contents of reg6
DW_OP_reg7 = 0x57, // Contents of reg7
DW_OP_reg8 = 0x58, // Contents of reg8
DW_OP_reg9 = 0x59, // Contents of reg9
DW_OP_reg10 = 0x5A, // Contents of reg10
DW_OP_reg11 = 0x5B, // Contents of reg11
DW_OP_reg12 = 0x5C, // Contents of reg12
DW_OP_reg13 = 0x5D, // Contents of reg13
DW_OP_reg14 = 0x5E, // Contents of reg14
DW_OP_reg15 = 0x5F, // Contents of reg15
DW_OP_reg16 = 0x60, // Contents of reg16
DW_OP_reg17 = 0x61, // Contents of reg17
DW_OP_reg18 = 0x62, // Contents of reg18
DW_OP_reg19 = 0x63, // Contents of reg19
DW_OP_reg20 = 0x64, // Contents of reg20
DW_OP_reg21 = 0x65, // Contents of reg21
DW_OP_reg22 = 0x66, // Contents of reg22
DW_OP_reg23 = 0x67, // Contents of reg23
DW_OP_reg24 = 0x68, // Contents of reg24
DW_OP_reg25 = 0x69, // Contents of reg25
DW_OP_reg26 = 0x6A, // Contents of reg26
DW_OP_reg27 = 0x6B, // Contents of reg27
DW_OP_reg28 = 0x6C, // Contents of reg28
DW_OP_reg29 = 0x6D, // Contents of reg29
DW_OP_reg30 = 0x6E, // Contents of reg30
DW_OP_reg31 = 0x6F, // Contents of reg31
DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset
DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset
DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset
DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset
DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset
DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset
DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset
DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset
DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset
DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset
DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset
DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset
DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset
DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset
DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset
DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset
DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset
DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset
DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset
DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset
DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset
DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset
DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset
DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset
DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset
DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset
DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset
DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset
DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset
DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset
DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset
DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset
DW_OP_regx = 0x90, // ULEB128 register
DW_OP_fbreg = 0x91, // SLEB128 offset
DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset
DW_OP_piece = 0x93, // ULEB128 size of piece addressed
DW_OP_deref_size = 0x94, // 1-byte size of data retrieved
DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved
DW_OP_nop = 0x96,
DW_OP_push_object_addres = 0x97,
DW_OP_call2 = 0x98, // 2-byte offset of DIE
DW_OP_call4 = 0x99, // 4-byte offset of DIE
DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE
DW_OP_lo_user = 0xE0,
DW_OP_APPLE_uninit = 0xF0,
DW_OP_hi_user = 0xFF
};
#endif

49
src/libunwind_priv.h Normal file
View File

@ -0,0 +1,49 @@
/* -*- mode: C++; c-basic-offset: 4; -*-
*
* Copyright (c) 2008 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#ifndef __LIBUNWIND_PRIV__
#define __LIBUNWIND_PRIV__
#include <libunwind.h>
#ifdef __cplusplus
extern "C" {
#endif
// SPI
extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
// IPI
extern void _unw_add_dynamic_fde(unw_word_t fde);
extern void _unw_remove_dynamic_fde(unw_word_t fde);
#ifdef __cplusplus
}
#endif
#endif

380
src/libuwind.cxx Normal file
View File

@ -0,0 +1,380 @@
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
* Copyright (c) 2007-2008 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <mach/mach_types.h>
#include <mach/machine.h>
#include <new>
#include "libunwind.h"
#include "libunwind_priv.h"
#include "UnwindCursor.hpp"
using namespace libunwind;
// setup debug logging hooks
INITIALIZE_DEBUG_PRINT_API
INITIALIZE_DEBUG_PRINT_UNWINDING
#if __ppc__ || __i386__ || __x86_64__
// internal object to represent this processes address space
static LocalAddressSpace sThisAddressSpace;
///
/// record the registers and stack position of the caller
///
extern int unw_getcontext(unw_context_t*);
// note: unw_getcontext() implemented in assembly
///
/// create a cursor of a thread in this process given 'context' recorded by unw_getcontext()
///
EXPORT int unw_init_local(unw_cursor_t* cursor, unw_context_t* context)
{
DEBUG_PRINT_API("unw_init_local(cursor=%p, context=%p)\n", cursor, context);
// use "placement new" to allocate UnwindCursor in the cursor buffer
#if __i386__
new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_x86>(context, sThisAddressSpace);
#elif __x86_64__
new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_x86_64>(context, sThisAddressSpace);
#elif __ppc__
new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_ppc>(context, sThisAddressSpace);
#endif
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
co->setInfoBasedOnIPRegister();
return UNW_ESUCCESS;
}
#if UNW_REMOTE
EXPORT unw_addr_space_t unw_local_addr_space = (unw_addr_space_t)&sThisAddressSpace;
///
/// create a cursor into a thread in another process
///
EXPORT int unw_init_remote_thread(unw_cursor_t* cursor, unw_addr_space_t as, thread_t thread)
{
// special case: unw_init_remote(xx, unw_local_addr_space, xx)
if ( as == (unw_addr_space_t)&sThisAddressSpace )
return unw_init_local(cursor, NULL); //FIXME
// use "placement new" to allocate UnwindCursor in the cursor buffer
switch ( as->cpuType ) {
case CPU_TYPE_I386:
new ((void*)cursor) UnwindCursor<OtherAddressSpace<Pointer32<LittleEndian> >,
Registers_x86>(((unw_addr_space_i386*)as)->oas, thread);
break;
case CPU_TYPE_X86_64:
new ((void*)cursor) UnwindCursor<OtherAddressSpace<Pointer64<LittleEndian> >,
Registers_x86_64>(((unw_addr_space_x86_64*)as)->oas, thread);
break;
case CPU_TYPE_POWERPC:
new ((void*)cursor) UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >,
Registers_ppc>(((unw_addr_space_ppc*)as)->oas, thread);
break;
default:
return UNW_EUNSPEC;
}
return UNW_ESUCCESS;
}
static bool rosetta(task_t task)
{
return false; // FIXME
}
static bool is64bit(task_t task)
{
return false; // FIXME
}
///
/// create an address_space object for use in examining another task
///
EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task)
{
#if __i386__
if ( rosetta(task) ) {
unw_addr_space_ppc* as = new unw_addr_space_ppc(task);
as->taskPort = task;
as->cpuType = CPU_TYPE_POWERPC;
//as->oas
}
else if ( is64bit(task) ) {
unw_addr_space_x86_64* as = new unw_addr_space_x86_64(task);
as->taskPort = task;
as->cpuType = CPU_TYPE_X86_64;
//as->oas
}
else {
unw_addr_space_i386* as = new unw_addr_space_i386(task);
as->taskPort = task;
as->cpuType = CPU_TYPE_I386;
//as->oas
}
#else
// FIXME
#endif
}
///
/// delete an address_space object
///
EXPORT void unw_destroy_addr_space(unw_addr_space_t asp)
{
switch ( asp->cpuType ) {
#if __i386__ || __x86_64__
case CPU_TYPE_I386:
{
unw_addr_space_i386* as = (unw_addr_space_i386*)asp;
delete as;
}
break;
case CPU_TYPE_X86_64:
{
unw_addr_space_x86_64* as = (unw_addr_space_x86_64*)asp;
delete as;
}
break;
#endif
case CPU_TYPE_POWERPC:
{
unw_addr_space_ppc* as = (unw_addr_space_ppc*)asp;
delete as;
}
break;
}
}
#endif // UNW_REMOTE
///
/// get value of specified register at cursor position in stack frame
///
EXPORT int unw_get_reg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_word_t* value)
{
DEBUG_PRINT_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n", cursor, regNum, value);
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
if ( co->validReg(regNum) ) {
*value = co->getReg(regNum);
return UNW_ESUCCESS;
}
return UNW_EBADREG;
}
///
/// set value of specified register at cursor position in stack frame
///
EXPORT int unw_set_reg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_word_t value)
{
DEBUG_PRINT_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n", cursor, regNum, value);
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
if ( co->validReg(regNum) ) {
co->setReg(regNum, value);
// specical case altering IP to re-find info (being called by personality function)
if ( regNum == UNW_REG_IP ) {
unw_proc_info_t info;
co->getInfo(&info);
uint64_t orgArgSize = info.gp;
uint64_t orgFuncStart = info.start_ip;
co->setInfoBasedOnIPRegister(false);
// and adjust REG_SP if there was a DW_CFA_GNU_args_size
if ( (orgFuncStart == info.start_ip) && (orgArgSize != 0) )
co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + orgArgSize);
}
return UNW_ESUCCESS;
}
return UNW_EBADREG;
}
///
/// get value of specified float register at cursor position in stack frame
///
EXPORT int unw_get_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_fpreg_t* value)
{
DEBUG_PRINT_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n", cursor, regNum, value);
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
if ( co->validFloatReg(regNum) ) {
*value = co->getFloatReg(regNum);
return UNW_ESUCCESS;
}
return UNW_EBADREG;
}
///
/// set value of specified float register at cursor position in stack frame
///
EXPORT int unw_set_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_fpreg_t value)
{
DEBUG_PRINT_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n", cursor, regNum, value);
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
if ( co->validFloatReg(regNum) ) {
co->setFloatReg(regNum, value);
return UNW_ESUCCESS;
}
return UNW_EBADREG;
}
///
/// move cursor to next frame
///
EXPORT int unw_step(unw_cursor_t* cursor)
{
DEBUG_PRINT_API("unw_step(cursor=%p)\n", cursor);
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
return co->step();
}
///
/// get unwind info at cursor position in stack frame
///
EXPORT int unw_get_proc_info(unw_cursor_t* cursor, unw_proc_info_t* info)
{
DEBUG_PRINT_API("unw_get_proc_info(cursor=%p, &info=%p)\n", cursor, info);
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
co->getInfo(info);
if ( info->end_ip == 0 )
return UNW_ENOINFO;
else
return UNW_ESUCCESS;
}
///
/// resume execution at cursor position (aka longjump)
///
EXPORT int unw_resume(unw_cursor_t* cursor)
{
DEBUG_PRINT_API("unw_resume(cursor=%p)\n", cursor);
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
co->jumpto();
return UNW_EUNSPEC;
}
///
/// get name of function at cursor position in stack frame
///
EXPORT int unw_get_proc_name(unw_cursor_t* cursor, char* buf, size_t bufLen, unw_word_t* offset)
{
DEBUG_PRINT_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%ld)\n", cursor, buf, bufLen);
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
if ( co->getFunctionName(buf, bufLen, offset) )
return UNW_ESUCCESS;
else
return UNW_EUNSPEC;
}
///
/// checks if a register is a floating-point register
///
EXPORT int unw_is_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum)
{
DEBUG_PRINT_API("unw_is_fpreg(cursor=%p, regNum=%d)\n", cursor, regNum);
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
return co->validFloatReg(regNum);
}
///
/// checks if a register is a floating-point register
///
EXPORT const char* unw_regname(unw_cursor_t* cursor, unw_regnum_t regNum)
{
DEBUG_PRINT_API("unw_regname(cursor=%p, regNum=%d)\n", cursor, regNum);
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
return co->getRegisterName(regNum);
}
///
/// checks if current frame is signal trampoline
///
EXPORT int unw_is_signal_frame(unw_cursor_t* cursor)
{
DEBUG_PRINT_API("unw_is_signal_frame(cursor=%p)\n", cursor);
AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor;
return co->isSignalFrame();
}
#if !FOR_DYLD
///
/// SPI: walks cached dwarf entries
///
EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh))
{
DEBUG_PRINT_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", func);
DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
}
#endif // !FOR_DYLD
#if !FOR_DYLD
//
// IPI: for __register_frame()
//
void _unw_add_dynamic_fde(unw_word_t fde)
{
CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
const char* message = CFI_Parser<LocalAddressSpace>::decodeFDE(sThisAddressSpace, (LocalAddressSpace::pint_t)fde, & fdeInfo, &cieInfo);
if ( message == NULL ) {
// dynamically registered FDEs don't have a mach_header group they are in. Use fde as mh_group
unw_word_t mh_group = fdeInfo.fdeStart;
DwarfFDECache<LocalAddressSpace>::add(mh_group, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart);
}
else {
DEBUG_MESSAGE("_unw_add_dynamic_fde: bad fde: %s", message);
}
}
//
// IPI: for __deregister_frame()
//
void _unw_remove_dynamic_fde(unw_word_t fde)
{
// fde is own mh_group
DwarfFDECache<LocalAddressSpace>::removeAllIn(fde);
}
#endif
#endif // __ppc__ || __i386__ || __x86_64__

229
src/unw_getcontext.S Normal file
View File

@ -0,0 +1,229 @@
#if __i386__ || __x86_64__ || __ppc__
.text
.globl _unw_getcontext
_unw_getcontext:
#endif // __i386__ || __x86_64__ || __ppc__
#if __i386__
#
# extern int unw_getcontext(unw_context_t* thread_state)
#
# On entry:
# + +
# +-----------------------+
# + thread_state pointer +
# +-----------------------+
# + return address +
# +-----------------------+ <-- SP
# + +
#
push %eax
movl 8(%esp), %eax
movl %ebx, 4(%eax)
movl %ecx, 8(%eax)
movl %edx, 12(%eax)
movl %edi, 16(%eax)
movl %esi, 20(%eax)
movl %ebp, 24(%eax)
movl %esp, %edx
addl $8, %edx
movl %edx, 28(%eax) # store what sp was at call site as esp
# skip ss
# skip eflags
movl 4(%esp), %edx
movl %edx, 40(%eax) # store return address as eip
# skip cs
# skip ds
# skip es
# skip fs
# skip gs
movl (%esp), %edx
movl %edx, (%eax) # store original eax
popl %eax
xorl %eax, %eax # return UNW_ESUCCESS
ret
#elif __x86_64__
#
# extern int unw_getcontext(unw_context_t* thread_state)
#
# On entry:
# thread_state pointer is in rdi
#
movq %rax, (%rdi)
movq %rbx, 8(%rdi)
movq %rcx, 16(%rdi)
movq %rdx, 24(%rdi)
movq %rdi, 32(%rdi)
movq %rsi, 40(%rdi)
movq %rbp, 48(%rdi)
movq %rsp, 56(%rdi)
addq $8, 56(%rdi)
movq %r8, 64(%rdi)
movq %r9, 72(%rdi)
movq %r10, 80(%rdi)
movq %r11, 88(%rdi)
movq %r12, 96(%rdi)
movq %r13,104(%rdi)
movq %r14,112(%rdi)
movq %r15,120(%rdi)
movq (%rsp),%rsi
movq %rsi,128(%rdi) # store return address as rip
# skip rflags
# skip cs
# skip fs
# skip gs
xorl %eax, %eax # return UNW_ESUCCESS
ret
#elif __ppc__
;
; extern int unw_getcontext(unw_context_t* thread_state)
;
; On entry:
; thread_state pointer is in r3
;
stw r0, 8(r3)
mflr r0
stw r0, 0(r3) ; store lr as ssr0
stw r1, 12(r3)
stw r2, 16(r3)
stw r3, 20(r3)
stw r4, 24(r3)
stw r5, 28(r3)
stw r6, 32(r3)
stw r7, 36(r3)
stw r8, 40(r3)
stw r9, 44(r3)
stw r10, 48(r3)
stw r11, 52(r3)
stw r12, 56(r3)
stw r13, 60(r3)
stw r14, 64(r3)
stw r15, 68(r3)
stw r16, 72(r3)
stw r17, 76(r3)
stw r18, 80(r3)
stw r19, 84(r3)
stw r20, 88(r3)
stw r21, 92(r3)
stw r22, 96(r3)
stw r23,100(r3)
stw r24,104(r3)
stw r25,108(r3)
stw r26,112(r3)
stw r27,116(r3)
stw r28,120(r3)
stw r29,124(r3)
stw r30,128(r3)
stw r31,132(r3)
; save VRSave register
mfspr r0,256
stw r0,156(r3)
; save CR registers
mfcr r0
stw r0,136(r3)
; save CTR register
mfctr r0
stw r0,148(r3)
; save float registers
stfd f0, 160(r3)
stfd f1, 168(r3)
stfd f2, 176(r3)
stfd f3, 184(r3)
stfd f4, 192(r3)
stfd f5, 200(r3)
stfd f6, 208(r3)
stfd f7, 216(r3)
stfd f8, 224(r3)
stfd f9, 232(r3)
stfd f10,240(r3)
stfd f11,248(r3)
stfd f12,256(r3)
stfd f13,264(r3)
stfd f14,272(r3)
stfd f15,280(r3)
stfd f16,288(r3)
stfd f17,296(r3)
stfd f18,304(r3)
stfd f19,312(r3)
stfd f20,320(r3)
stfd f21,328(r3)
stfd f22,336(r3)
stfd f23,344(r3)
stfd f24,352(r3)
stfd f25,360(r3)
stfd f26,368(r3)
stfd f27,376(r3)
stfd f28,384(r3)
stfd f29,392(r3)
stfd f30,400(r3)
stfd f31,408(r3)
; save vector registers
subi r4,r1,16
rlwinm r4,r4,0,0,27 ; mask low 4-bits
; r4 is now a 16-byte aligned pointer into the red zone
#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \
stvx _vec,0,r4 @\
lwz r5, 0(r4) @\
stw r5, _offset(r3) @\
lwz r5, 4(r4) @\
stw r5, _offset+4(r3) @\
lwz r5, 8(r4) @\
stw r5, _offset+8(r3) @\
lwz r5, 12(r4) @\
stw r5, _offset+12(r3)
SAVE_VECTOR_UNALIGNED( v0, 424+0x000)
SAVE_VECTOR_UNALIGNED( v1, 424+0x010)
SAVE_VECTOR_UNALIGNED( v2, 424+0x020)
SAVE_VECTOR_UNALIGNED( v3, 424+0x030)
SAVE_VECTOR_UNALIGNED( v4, 424+0x040)
SAVE_VECTOR_UNALIGNED( v5, 424+0x050)
SAVE_VECTOR_UNALIGNED( v6, 424+0x060)
SAVE_VECTOR_UNALIGNED( v7, 424+0x070)
SAVE_VECTOR_UNALIGNED( v8, 424+0x080)
SAVE_VECTOR_UNALIGNED( v9, 424+0x090)
SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0)
SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0)
SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0)
SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0)
SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0)
SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0)
SAVE_VECTOR_UNALIGNED(v16, 424+0x100)
SAVE_VECTOR_UNALIGNED(v17, 424+0x110)
SAVE_VECTOR_UNALIGNED(v18, 424+0x120)
SAVE_VECTOR_UNALIGNED(v19, 424+0x130)
SAVE_VECTOR_UNALIGNED(v20, 424+0x140)
SAVE_VECTOR_UNALIGNED(v21, 424+0x150)
SAVE_VECTOR_UNALIGNED(v22, 424+0x160)
SAVE_VECTOR_UNALIGNED(v23, 424+0x170)
SAVE_VECTOR_UNALIGNED(v24, 424+0x180)
SAVE_VECTOR_UNALIGNED(v25, 424+0x190)
SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0)
SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0)
SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0)
SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0)
SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0)
SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0)
li r3, 0 ; return UNW_ESUCCESS
blr
#endif

View File

@ -0,0 +1,59 @@
//
// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions
// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions -fomit-frame-pointer
// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions -Wl,-no_compact_unwind
// TEST-OPTIONS: backtrace2.c -arch x86_64
// TEST-OPTIONS: backtrace2.c -arch x86_64 -fomit-frame-pointer
// TEST-OPTIONS: backtrace2.c -arch x86_64 -Wl,-no_compact_unwind
// TEST-OPTIONS: backtrace2.c -arch ppc -fexceptions
//
// Tests _Unwind_Backtrace()
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include "unwind.h"
// put intermediate function into another file so compiler does not optimze away
extern int foo();
static const char* expected[] = { "bar", "foo", "main" };
static int step = 0;
static _Unwind_Reason_Code handler(struct _Unwind_Context* context, void* ref)
{
if ( step > 2 )
return _URC_NORMAL_STOP;
struct dl_info dyldInfo;
if ( dladdr((void*)_Unwind_GetIP(context), &dyldInfo) ) {
if ( strcmp(dyldInfo.dli_sname, expected[step]) != 0 ) {
fprintf(stderr, "unexpected frame %s\n", dyldInfo.dli_sname);
exit(1);
}
++step;
}
else {
exit(1);
}
return _URC_NO_REASON;
}
int bar()
{
_Unwind_Backtrace(&handler, NULL);
return (step == 2);
}
int main()
{
return foo();
}

View File

@ -0,0 +1,54 @@
//
// TEST-OPTIONS: -arch i386
// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64
// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch ppc
//
// Tests _Unwind_ForcedUnwind()
//
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "unwind.h"
static bool exceptionCaught = false;
static _Unwind_Reason_Code stop_func(int version, _Unwind_Action actions, uint64_t exceptionClass,
_Unwind_Exception* exceptionObject, _Unwind_Context* context, void* stop_parameter)
{
if ( actions & _UA_END_OF_STACK ) {
if ( exceptionCaught )
exit(0);
else
exit(1);
}
return _URC_NO_REASON;
}
void test()
{
try {
_Unwind_Exception* except_obj = (_Unwind_Exception*)calloc(sizeof(_Unwind_Exception), 1);
_Unwind_ForcedUnwind(except_obj, stop_func, NULL);
}
catch(...) {
// forced unwindind should run this catch clause
exceptionCaught = true;
throw;
}
}
int main()
{
test();
return 1;
}

71
testsuite/backtrace.c Normal file
View File

@ -0,0 +1,71 @@
//
// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions
// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions -fomit-frame-pointer
// TEST-OPTIONS: backtrace2.c -arch i386 -fexceptions -Wl,-no_compact_unwind
// TEST-OPTIONS: backtrace2.c -arch x86_64
// TEST-OPTIONS: backtrace2.c -arch x86_64 -fomit-frame-pointer
// TEST-OPTIONS: backtrace2.c -arch x86_64 -Wl,-no_compact_unwind
// TEST-OPTIONS: backtrace2.c -arch ppc -fexceptions
//
// Basic backtrace test
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "libunwind.h"
static const char* other_expected[] = { "bar", "foo", "work", "_pthread_start", NULL, NULL };
static const char* main_expected[] = { "bar", "foo", "main", NULL, NULL };
// put intermediate function into another file so compiler does not optimze away
extern int foo(const char** list);
int bar(const char** list)
{
char functionName[64];
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t offset;
int index = 0;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
do {
unw_get_proc_name(&cursor, functionName, 64, &offset);
//fprintf(stderr, "in function: %s\n", functionName);
if ( (list[index] != NULL) && (strcmp(functionName, list[index]) != 0) ) {
//fprintf(stderr, "unexpected function: %s\n", functionName);
exit(1);
}
++index;
} while (unw_step(&cursor) > 0);
return 0;
}
static void* work(void* arg)
{
foo((const char**)arg);
return NULL;
}
int main()
{
// test back traces on another thread
pthread_t worker1;
if ( pthread_create(&worker1, NULL, work, other_expected) != 0 ) {
exit(0);
}
void* result;
pthread_join(worker1, &result);
// test back traces on main thread
return foo(main_expected);
}

7
testsuite/backtrace2.c Normal file
View File

@ -0,0 +1,7 @@
extern int bar(const char** list);
int foo(const char** list)
{
return bar(list);
}

View File

@ -0,0 +1,17 @@
all:
@g++ foo.cxx -dynamiclib -o libfoo.dylib -arch i386 -arch x86_64 -Wl,-no_compact_unwind
@gcc main.c -arch i386 -o main-i386
@./main-i386 && echo "PASS dwarf-cache-dlclose -arch i386"
@gcc main.c -arch x86_64 -o main-x86_64
@./main-x86_64 && echo "PASS dwarf-cache-dlclose -arch x86_64"
# @gcc main.c -arch ppc -o main-ppc
# @./main-ppc && echo "PASS dwarf-cache-dlclose -arch ppc"
clean:
@rm -f libfoo.dylib main-i386 main-x86_64 main-ppc

View File

@ -0,0 +1,20 @@
#include <stdio.h>
void bar()
{
throw "wow";
}
extern "C" void foo();
void foo()
{
try {
bar();
}
catch(...) {
//fprintf(stderr, "caught\n");
}
}

View File

@ -0,0 +1,58 @@
#include <stdio.h>
#include <libunwind.h>
#include <dlfcn.h>
extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
typedef void (*FooProc)();
static FooProc foo;
static bool fooInCache = false;
static void callback(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)
{
//fprintf(stderr, "ip_start = 0x%llX, ip_end = 0x%llX\n", ip_start, ip_end);
if ( (unw_word_t)(long)foo == ip_start )
fooInCache = true;
}
int main()
{
void* handle = dlopen("libfoo.dylib", RTLD_FIRST);
if ( handle == NULL ) {
printf("FAIL: dlopen could not load libfoo.dylib\n");
return 1;
}
foo = (FooProc)dlsym(handle, "foo");
if ( foo == NULL ) {
printf("FAIL: dlsym could not find foo\n");
return 1;
}
//fprintf(stderr, "foo=%p\n", foo);
(*foo)();
// verify foo is in cache
fooInCache = false;
unw_iterate_dwarf_unwind_cache(&callback);
if ( !fooInCache ) {
printf("FAIL: foo is not in cache\n");
return 1;
}
dlclose(handle);
//fprintf(stderr, "dlclose\n");
// verify foo is no longer in cache
fooInCache = false;
unw_iterate_dwarf_unwind_cache(&callback);
if ( fooInCache ){
printf("FAIL: foo is still in cache\n");
return 1;
}
return 0;
}

View File

@ -0,0 +1,139 @@
//
// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <mach/mach.h>
#include <libunwind.h>
#include "unwind.h"
// private keymgr stuff
#define KEYMGR_GCC3_DW2_OBJ_LIST 302
extern "C" {
extern void _keymgr_set_and_unlock_processwide_ptr(int key, void* ptr);
extern void* _keymgr_get_and_lock_processwide_ptr(int key);
};
// undocumented libgcc "struct object"
struct libgcc_object
{
void* start;
void* unused1;
void* unused2;
void* fde;
unsigned long encoding;
void* fde_end;
libgcc_object* next;
};
// undocumented libgcc "struct km_object_info" referenced by KEYMGR_GCC3_DW2_OBJ_LIST
struct libgcc_object_info {
struct libgcc_object* seen_objects;
struct libgcc_object* unseen_objects;
unsigned spare[2];
};
// Some application have reverse engineer libgcc and do the equivalent
// of my_keymgr_register_frame() to register dynamically created code.
static void my_keymgr_register_frame(void* fde)
{
// acquire exclusive access to libgcc_object_info
libgcc_object_info* head = (libgcc_object_info*)_keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
// create new object
libgcc_object* ob = (libgcc_object*)calloc(sizeof(libgcc_object), 1);
ob->fde = fde;
// insert new object into linked list
ob->next = head->unseen_objects;
head->unseen_objects = ob;
// release libgcc_object_info
_keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
}
void check(bool shouldFindMain)
{
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t offset;
bool foundMain = false;
char functionName[256];
//fprintf(stderr, "check(shouldFindMain=%d)\n", shouldFindMain);
int level = 1;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
do {
unw_get_proc_name(&cursor, functionName, 64, &offset);
//fprintf(stderr, "level=%d in function: %s\n", level, functionName);
if ( strcmp(functionName, "main") == 0 )
foundMain = true;
++level;
strcpy(functionName, "junk");
} while (unw_step(&cursor) > 0);
if ( foundMain == shouldFindMain )
return;
fprintf(stderr, "failing because shouldFindMain=%d and foundMain=%d\n", shouldFindMain, foundMain);
exit(1);
}
void foo(bool shouldFindMain, void (*func)(bool))
{
(*func)(shouldFindMain);
__asm__ volatile(""); // disable tail call optimization
}
typedef void (*checkFuncProc)(bool shouldFindMain, void (*func)(bool));
int main()
{
struct dwarf_eh_bases junk;
const void* foo_eh_src = _Unwind_Find_FDE((void*)((long)&foo + 1), &junk);
// copy foo and its fde to a dynamically allocated buffer
unsigned long deltaToFDE = (uintptr_t)foo_eh_src - (uintptr_t)&foo;
unsigned long size = deltaToFDE + 100;
size = ((size + 4095) & (-4096));
vm_address_t addr = 0;
if ( vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
exit(1);
memcpy((void*)addr, (void*)&foo, size);
mprotect((void*)addr, size, PROT_READ|PROT_EXEC);
// make pointer to copy of foo and copy of fde
checkFuncProc checkFunc = (checkFuncProc)addr;
void* foo_eh = (void*)(addr + deltaToFDE);
// call check() with unwind info unregistered, verify fails
(*checkFunc)(false, check);
// call check() with unwind info registered, verify succeeds
__register_frame(foo_eh);
(*checkFunc)(true, check);
// call check() with unwind info unregistered, verify fails
__deregister_frame(foo_eh);
(*checkFunc)(false, check);
// call check() with unwind info added via keymgr, verify succeeds
my_keymgr_register_frame(foo_eh);
(*checkFunc)(true, check);
return 0;
}

39
testsuite/end_of_stack.c Normal file
View File

@ -0,0 +1,39 @@
//
// TEST-OPTIONS: -arch i386 -fexceptions
// TEST-OPTIONS: -arch i386 -fexceptions -fomit-frame-pointer
// TEST-OPTIONS: -arch i386 -fexceptions -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64
// TEST-OPTIONS: -arch x86_64 -fomit-frame-pointer
// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch ppc -fexceptions
//
// Tests _Unwind_RaiseException() returns _URC_END_OF_STACK if there is nothing to catch the exception
//
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "unwind.h"
struct _Unwind_Exception ex;
int main()
{
ex.exception_class = ((uint64_t)'mymy' << 32) | (uint64_t)'exex';
ex.exception_cleanup = NULL;
ex.private_1 = 0;
ex.private_2 = 0;
_Unwind_Reason_Code result = _Unwind_RaiseException(&ex);
if ( result == _URC_END_OF_STACK )
return 0;
else
return 1;
}

View File

@ -0,0 +1,240 @@
// TEST-OPTIONS: -arch x86_64 -lstdc++ -Wl,-no_compact_unwind
.section __TEXT,__text,regular,pure_instructions
.globl __Z3foov
.align 4, 0x90
__Z3foov:
Leh_func_begin1:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
subq $16, %rsp
Ltmp2:
movabsq $4, %rax
movq %rax, %rdi
callq ___cxa_allocate_exception
movq %rax, -16(%rbp)
movq -16(%rbp), %rax
movl $10, (%rax)
movq -16(%rbp), %rax
movq __ZTIi@GOTPCREL(%rip), %rcx
leaq (%rcx), %rcx
movabsq $0, %rdx
movq %rax, %rdi
movq %rcx, %rsi
callq ___cxa_throw
Leh_func_end1:
.globl _main
.align 4, 0x90
_main:
Leh_func_begin2:
pushq %rbp
Ltmp6:
movq %rsp, %rbp
Ltmp7:
subq $48, %rsp
Ltmp8:
movl $1, -28(%rbp)
movl $2, -28(%rbp)
Ltmp3:
callq __Z3foov
Ltmp4:
jmp LBB2_1
LBB2_1:
movl $3, -28(%rbp)
jmp LBB2_10
LBB2_2:
movq -40(%rbp), %rax
movq %rax, %rdi
callq ___cxa_begin_catch
movq %rax, -24(%rbp)
movq -24(%rbp), %rax
movl (%rax), %eax
movl %eax, -32(%rbp)
movl -28(%rbp), %eax
cmpl $2, %eax
je LBB2_4
movl $1, -12(%rbp)
movl -12(%rbp), %eax
movl %eax, -12(%rbp)
movl -12(%rbp), %eax
movl %eax, -12(%rbp)
movl $0, -8(%rbp)
jmp LBB2_7
LBB2_4:
movl -32(%rbp), %eax
cmpl $10, %eax
je LBB2_6
movl $1, -12(%rbp)
movl -12(%rbp), %eax
movl %eax, -12(%rbp)
movl -12(%rbp), %eax
movl %eax, -12(%rbp)
movl $0, -8(%rbp)
jmp LBB2_7
LBB2_6:
movl $4, -28(%rbp)
movl $1, -8(%rbp)
LBB2_7:
callq ___cxa_end_catch
movl -8(%rbp), %eax
cmpl $1, %eax
jne LBB2_9
jmp LBB2_10
LBB2_9:
jmp LBB2_13
LBB2_10:
movl -28(%rbp), %eax
cmpl $4, %eax
jne LBB2_12
movl $0, -12(%rbp)
jmp LBB2_13
LBB2_12:
movl $1, -12(%rbp)
LBB2_13:
movl -12(%rbp), %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
addq $48, %rsp
popq %rbp
ret
LBB2_15:
Ltmp5:
movq %rax, -40(%rbp)
movq -40(%rbp), %rax
movl %edx, %eax
movl %eax, -44(%rbp)
movl $2, %eax
movl -44(%rbp), %ecx
cmpl %eax, %ecx
je LBB2_2
movq -40(%rbp), %rax
movq %rax, %rdi
callq __Unwind_Resume_or_Rethrow
Leh_func_end2:
.section __TEXT,__gcc_except_tab
.align 2
GCC_except_table2:
Lexception2:
.byte 255
.byte 155
.byte 168
.space 1
.byte 3
.byte 26
Lset0 = Ltmp3-Leh_func_begin2
.long Lset0
Lset1 = Ltmp4-Ltmp3
.long Lset1
Lset2 = Ltmp5-Leh_func_begin2
.long Lset2
.byte 3
Lset3 = Ltmp4-Leh_func_begin2
.long Lset3
Lset4 = Leh_func_end2-Ltmp4
.long Lset4
.long 0
.byte 0
.byte 1
.byte 0
.byte 2
.byte 125
.long __ZTIi@GOTPCREL+4
.long 0
.align 2
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame0:
Lsection_eh_frame:
Leh_frame_common:
Lset5 = Leh_frame_common_end-Leh_frame_common_begin
.long Lset5
Leh_frame_common_begin:
.long 0
.byte 1
.asciz "zPLR"
.byte 1
.byte 120
.byte 16
.byte 7
.byte 155
.long ___gxx_personality_v0@GOTPCREL+4
.byte 0x1B // lsda encoding DW_EH_PE_pcrel + DW_EH_PE_sdata4
.byte 16
.byte 12
.byte 7
.byte 8
.byte 144
.byte 1
.align 3
Leh_frame_common_end:
.globl __Z3foov.eh
__Z3foov.eh:
Lset6 = Leh_frame_end1-Leh_frame_begin1
.long Lset6
Leh_frame_begin1:
Lset7 = Leh_frame_begin1-Leh_frame_common
.long Lset7
Ltmp9:
.quad Leh_func_begin1-Ltmp9
Lset8 = Leh_func_end1-Leh_func_begin1
.quad Lset8
.byte 4
.long 0
.byte 4
Lset9 = Ltmp0-Leh_func_begin1
.long Lset9
.byte 14
.byte 16
.byte 134
.byte 2
.byte 4
Lset10 = Ltmp1-Ltmp0
.long Lset10
.byte 13
.byte 6
.align 3
Leh_frame_end1:
.globl _main.eh
_main.eh:
Lset11 = Leh_frame_end2-Leh_frame_begin2
.long Lset11
Leh_frame_begin2:
Lset12 = Leh_frame_begin2-Leh_frame_common
.long Lset12
Ltmp10:
.quad Leh_func_begin2-Ltmp10
Lset13 = Leh_func_end2-Leh_func_begin2
.quad Lset13
.byte 4
Ltmp11:
.long Lexception2-Ltmp11
.byte 4
Lset14 = Ltmp6-Leh_func_begin2
.long Lset14
.byte 14
.byte 16
.byte 134
.byte 2
.byte 4
Lset15 = Ltmp7-Ltmp6
.long Lset15
.byte 13
.byte 6
.align 3
Leh_frame_end2:
.subsections_via_symbols

View File

@ -0,0 +1,33 @@
// TEST-OPTIONS: -arch i386
// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64
// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch ppc
int foo() { throw 10; }
int main()
{
int state = 1;
try {
state = 2;
foo();
state = 3;
}
catch (int x) {
if ( state != 2 )
return 1;
if ( x != 10 )
return 1;
state = 4;
}
if ( state == 4 )
return 0;
else
return 1;
}

View File

@ -0,0 +1,54 @@
// TEST-OPTIONS: -arch i386
// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64
// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch ppc
#include <stdio.h>
int global = 0;
int bar()
{
global = 1;
throw 10;
}
void foo()
{
try {
bar();
}
catch(int x) {
global = 2;
throw x;
}
}
int main()
{
int state = 1;
try {
state = 2;
foo();
state = 3;
}
catch (int x) {
if ( state != 2 )
return 1;
if ( x != 10 )
return 1;
state = 4;
}
if ( (state == 4) && (global == 2) )
return 0;
else
return 1;
}

View File

@ -0,0 +1,52 @@
// TEST-OPTIONS: -x c exception_missing_eh2.c -arch i386
// TEST-OPTIONS: -x c exception_missing_eh2.c -arch i386 -Wl,-no_compact_unwind
// TEST-OPTIONS: -x c exception_missing_eh2.c -arch ppc
// TEST-OPTIONS: exception_missing_eh2_x86_64.s -arch x86_64
// TEST-OPTIONS: exception_missing_eh2_x86_64.s -arch x86_64 -Wl,-no_compact_unwind
#include <stdlib.h>
#include <exception>
extern "C" {
extern int bar();
extern int foo();
}
int foo() { throw 10; }
static void term()
{
// terminate called, as we want
exit(0);
}
int main()
{
std::set_terminate(term);
int state = 1;
try {
state = 2;
// bar() calls foo() which throws
// but, bar is missing eh info, so terminate() is called
bar();
state = 3;
}
catch (int x) {
if ( state != 2 )
return 1;
if ( x != 10 )
return 1;
state = 4;
}
// should not get here
exit(1);
}

View File

@ -0,0 +1,14 @@
// bar() calls foo()
// this is in a separate file because we want bar() to not have eh info
extern int foo();
int global;
int bar() {
int x = foo();
++global; // to prevent tail call optimization
return x;
}

View File

@ -0,0 +1,13 @@
/* Need assembly to create bar() without eh info */
.text
.globl _bar
_bar:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $0, %eax
call _foo
leave
ret

View File

@ -0,0 +1,54 @@
// TEST-OPTIONS: -arch i386
// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64
// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch ppc
#include <stdio.h>
int global = 0;
int bar()
{
global = 1;
throw 10;
}
void foo()
{
try {
bar();
}
catch(int x) {
global = 2;
throw;
}
}
int main()
{
int state = 1;
try {
state = 2;
foo();
state = 3;
}
catch (int x) {
if ( state != 2 )
return 1;
if ( x != 10 )
return 1;
state = 4;
}
if ( (state == 4) && (global == 2) )
return 0;
else
return 1;
}

View File

@ -0,0 +1,57 @@
// TEST-OPTIONS: -arch i386
// TEST-OPTIONS: -arch x86_64
// TEST-OPTIONS: -arch ppc
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <new>
void segfault(int sig)
{
::signal(SIGBUS, SIG_DFL);
::signal(SIGSEGV, SIG_DFL);
//fprintf(stderr, "bus error handler for pid=%d\n", getpid());
//sleep(30);
throw "seg fault";
}
__attribute__((noinline)) void boom(int* p)
{
// do allocation, so compiler won't optimize away catch clause in main()
int* x = new int[100];
*x = *p;
}
int main()
{
::signal(SIGBUS, segfault);
::signal(SIGSEGV, segfault);
int state = 1;
try {
state = 2;
boom(NULL);
state = 3;
}
catch (const char* msg) {
//fprintf(stderr, "caught %s\n", msg);
if ( state != 2 )
exit(1);
state = 4;
}
catch(...) {
//fprintf(stderr, "caught ...\n");
exit(1);
}
if ( state == 4 )
return 0;
else
return 1;
}

View File

@ -0,0 +1,48 @@
//
// TEST-OPTIONS: -arch i386 -fexceptions -fomit-frame-pointer -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch i386 -fexceptions -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64 -fomit-frame-pointer -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch ppc -fexceptions
//
// Basic _Unwind_FindEnclosingFunction test
//
// _Unwind_FindEnclosingFunction() is supposed to return the start of a
// function given an address in the function. It uses FDE info.
//
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "unwind.h"
int bar(int x)
{
// dummy call to force dwarf info generation
_Unwind_GetIP(NULL);
return x + 20;
}
int foo(int x)
{
// dummy call to force dwarf info generation
_Unwind_GetIP(NULL);
return x + 10;
}
int main()
{
uint8_t* addrInBar = (uint8_t*)bar + 4;
uint8_t* addrInFoo = (uint8_t*)foo + 4;
if ( _Unwind_FindEnclosingFunction(addrInBar) != &bar )
return 1;
if ( _Unwind_FindEnclosingFunction(addrInFoo) != &foo )
return 1;
return 0;
}

View File

@ -0,0 +1,50 @@
// TEST-OPTIONS: -arch x86_64 -framework Foundation
// TEST-OPTIONS: -arch x86_64 -framework Foundation -Wl,-no_compact_unwind
#include <Foundation/Foundation.h>
// private SPI for AppKit
extern int _NSAddAltHandler2(void (*proc)(NSException* exc, void* context), void* context);
int foo()
{
@throw [NSException exceptionWithName:NSGenericException reason:@"many" userInfo:nil];
}
static void handler(NSException* exc, void* context)
{
int* paltState = (int*)context;
*paltState = 1;
}
int main()
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int state = 1;
int altState = 0;
@try {
_NSAddAltHandler2(handler, &altState);
state = 2;
foo();
state = 3;
}
@catch(id exception) {
if ( state != 2 )
return 1;
if ( altState == 0 )
return 1;
if ( [[exception name] isEqualToString:NSGenericException] )
state = 4;
}
if ( state == 4 )
return 0;
else
return 1;
}

View File

@ -0,0 +1,36 @@
// TEST-OPTIONS: -arch x86_64 -framework Foundation
// TEST-OPTIONS: -arch x86_64 -framework Foundation -Wl,-no_compact_unwind
#include <Foundation/Foundation.h>
int foo()
{
@throw [NSException exceptionWithName:NSGenericException reason:@"many" userInfo:nil];
}
int main()
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int state = 1;
@try {
state = 2;
foo();
state = 3;
}
@catch(id exception) {
if ( state != 2 )
return 1;
if ( [[exception name] isEqualToString:NSGenericException] )
state = 4;
}
if ( state == 4 )
return 0;
else
return 1;
}

170
testsuite/personality.cxx Normal file
View File

@ -0,0 +1,170 @@
// TEST-OPTIONS: -arch i386
// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64
// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch ppc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include "unwind.h"
static __personality_routine realPersonality = (__personality_routine)dlsym(RTLD_DEFAULT, "__gxx_personality_v0");
int count = 0;
const char* actionString(_Unwind_Action act)
{
static char buffer[100];
buffer[0] = '\0';
if ( act & _UA_SEARCH_PHASE )
strcat(buffer, "_UA_SEARCH_PHASE ");
if ( act & _UA_CLEANUP_PHASE )
strcat(buffer, "_UA_CLEANUP_PHASE ");
if ( act & _UA_HANDLER_FRAME )
strcat(buffer, "_UA_HANDLER_FRAME ");
if ( act & _UA_FORCE_UNWIND )
strcat(buffer, "_UA_FORCE_UNWIND ");
if ( act & _UA_END_OF_STACK )
strcat(buffer, "_UA_END_OF_STACK ");
if ( act & 0xFFFFFFE0 )
strcat(buffer, "unknown bits ");
return buffer;
}
const char* reasonString(_Unwind_Reason_Code reason)
{
switch (reason) {
case _URC_NO_REASON:
return "_URC_NO_REASON";
case _URC_FOREIGN_EXCEPTION_CAUGHT:
return "_URC_FOREIGN_EXCEPTION_CAUGHT";
case _URC_FATAL_PHASE2_ERROR:
return "_URC_FATAL_PHASE2_ERROR";
case _URC_FATAL_PHASE1_ERROR:
return "_URC_FATAL_PHASE1_ERROR";
case _URC_NORMAL_STOP:
return "_URC_NORMAL_STOP";
case _URC_END_OF_STACK:
return "_URC_END_OF_STACK";
case _URC_HANDLER_FOUND:
return "_URC_HANDLER_FOUND";
case _URC_INSTALL_CONTEXT:
return "_URC_INSTALL_CONTEXT";
case _URC_CONTINUE_UNWIND:
return "_URC_CONTINUE_UNWIND";
}
return "unknown reason code";
}
bool fooCaught = false;
bool mainInnerCaught = false;
bool mainOuterCaught = false;
struct Expected {
bool fooCaught;
bool mainInnerCaught;
bool mainOuterCaught;
_Unwind_Action action;
_Unwind_Reason_Code result;
};
#define _UA_CLEANUP_PHASE_HANDLER_FRAME (_Unwind_Action)(_UA_CLEANUP_PHASE|_UA_HANDLER_FRAME)
const Expected shouldBe[] = {
{ false, false, false, _UA_SEARCH_PHASE, _URC_HANDLER_FOUND },
{ false, false, false, _UA_CLEANUP_PHASE_HANDLER_FRAME, _URC_INSTALL_CONTEXT },
{ true, false, false, _UA_SEARCH_PHASE, _URC_CONTINUE_UNWIND },
{ true, false, false, _UA_SEARCH_PHASE, _URC_HANDLER_FOUND },
{ true, false, false, _UA_CLEANUP_PHASE, _URC_INSTALL_CONTEXT },
{ true, false, false, _UA_CLEANUP_PHASE, _URC_CONTINUE_UNWIND },
{ true, false, false, _UA_CLEANUP_PHASE_HANDLER_FRAME, _URC_INSTALL_CONTEXT },
{ true, true, false, _UA_SEARCH_PHASE, _URC_HANDLER_FOUND },
{ true, true, false, _UA_CLEANUP_PHASE_HANDLER_FRAME, _URC_INSTALL_CONTEXT }
};
extern "C" {
__attribute__((visibility("hidden"))) _Unwind_Reason_Code __gxx_personality_v0(
int version, _Unwind_Action actions, uint64_t exceptionClass,
struct _Unwind_Exception* exceptionObject, _Unwind_Context* context)
{
_Unwind_Reason_Code result = (*realPersonality)(version, actions, exceptionClass,
exceptionObject, context);
//fprintf(stderr, "fooCaught=%d, mainInnerCaught=%d, mainOuterCaught=%d, ",
// fooCaught, mainInnerCaught, mainOuterCaught);
//fprintf(stderr, "personality(%d, %s, 0x%llX, %p, %p) => %s\n", version, actionString(actions),
// exceptionClass, exceptionObject, context, reasonString(result));
if ( shouldBe[count].fooCaught != fooCaught ) {
fprintf(stderr, "count=%d, fooCaught=%d\n", count, fooCaught);
abort();
}
if ( shouldBe[count].mainInnerCaught != mainInnerCaught ) {
fprintf(stderr, "count=%d, mainInnerCaught=%d\n", count, mainInnerCaught);
abort();
}
if ( shouldBe[count].mainOuterCaught != mainOuterCaught ) {
fprintf(stderr, "count=%d, mainOuterCaught=%d\n", count, mainOuterCaught);
abort();
}
if ( shouldBe[count].action != actions ) {
fprintf(stderr, "count=%d, actions=%s\n", count, actionString(actions));
abort();
}
if ( shouldBe[count].result != result ) {
fprintf(stderr, "count=%d, result=%s\n", count, reasonString(result));
abort();
}
if ( count++ > 12 )
abort();
return result;
}
}
int __attribute__((noinline)) bar()
{
throw 10;
}
void __attribute__((noinline)) foo()
{
try {
bar();
}
catch(int x) {
fooCaught = true;
throw;
}
}
int main()
{
try {
try {
foo();
}
catch (int x) {
mainInnerCaught = true;
throw;
}
}
catch (...) {
mainOuterCaught = true;
}
if ( count != 9 ) {
fprintf(stderr, "count=%d\n", count);
abort();
}
return 0;
}

View File

@ -0,0 +1,40 @@
// TEST-OPTIONS: -arch i386
// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64
// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind
#include <stdlib.h>
#include <exception>
int foo()
{
try {
throw 10;
}
catch (...) {
throw;
}
}
static void term()
{
// terminate called, as we want
exit(0);
}
int main()
{
std::set_terminate(term);
foo();
// should not get here
exit(1);
}

108
testsuite/run-all-tests.pl Normal file
View File

@ -0,0 +1,108 @@
#!/usr/bin/perl
use strict;
use warnings;
use File::stat;
use Cwd;
my $testCaseFilter = '*';
if ( $#ARGV == 0 ) {
$testCaseFilter = $ARGV[0];
}
my $useLocalDylib = 0;
my $headerPath = "-I../include -I../src";
if ( stat('../build/Debug/libunwind.dylib') ) {
printf "### running with ../build/Debug/libunwind.dylib ###\n";
$useLocalDylib = 1;
}
my $canRunPPC = 0;
if ( stat('/usr/libexec/oah/translate') ) {
# $canRunPPC = 1;
}
#
# Search current directory for all files with TEST-OPTIONS: comments
# Compile and link each file with specified options
# Execute result and print PASS or FAIL
#
my $path = shift;
# get list of dylibs linked against
open(FILE, "grep -H 'TEST-OPTIONS:' $testCaseFilter |");
$/ = "\n";
while ( <FILE> ) {
if ($_ =~ m/^(.+):.+TEST-OPTIONS:(.+)/) {
my $file = $1;
my $options = "$2";
my $ppc = 0;
if ( $options =~ /arch ppc/ ) {
$ppc = 1;
}
if ( $file !~ "run-all-tests.pl" ) {
my $exit;
if ( $ppc && !$canRunPPC ) {
# don't try to build ppc tests
}
elsif ( $file =~ /^(.+)\.cxx/ ) {
#printf "c++ $file $options $headerPath -o /tmp/run-all-tests.a.out\n";
$exit = system("c++ $file $options $headerPath -o /tmp/run-all-tests.a.out");
}
else {
#printf "cc $file $options $headerPath -o /tmp/run-all-tests.a.out\n";
$exit = system("cc $file $options $headerPath -o /tmp/run-all-tests.a.out");
}
if ( $ppc && ($useLocalDylib || !$canRunPPC) ) {
#printf "SKIP $file $options\n";
}
elsif ( $exit == 0 ) {
if ( $useLocalDylib ) {
$ENV{'DYLD_LIBRARY_PATH'} = '../build/Debug';
}
my $exit = system("/tmp/run-all-tests.a.out");
if ( $useLocalDylib ) {
$ENV{'DYLD_LIBRARY_PATH'} = '';
}
if ( $exit == 0 ) {
printf "PASS $file $options\n";
}
else {
printf "FAIL $file $options (runtime failure)\n";
}
}
else {
printf "FAIL $file $options (could not compile)\n";
}
}
}
}
close FILE;
#
# Search for .mk directories and run make in each one
#
my $cwd = getcwd();
open(FILE, "ls -1 |");
$/ = "\n";
while ( <FILE> ) {
if ($_ =~ m/^(.+\.mk)$/) {
my $dir = $1;
if ( ($testCaseFilter =~ /\*/) || ($dir =~ /$testCaseFilter/) ) {
if ( $useLocalDylib ) {
$ENV{'DYLD_LIBRARY_PATH'} = "$cwd/../build/Debug";
}
my $exit = system("cd $dir && make");
if ( $useLocalDylib ) {
$ENV{'DYLD_LIBRARY_PATH'} = '';
}
system("cd $dir && make clean");
}
}
}
close FILE;

View File

@ -0,0 +1,31 @@
// TEST-OPTIONS: -arch i386
// TEST-OPTIONS: -arch i386 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64
// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch ppc
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <exception>
void my_terminate() {
try {
throw;
} catch (char *s) {
if ( (s == NULL) || (strcmp(s, "my exception") != 0) )
exit(1);
//printf("caught rethrown %p %s\n", s, s);
exit(0);
}
}
int main()
{
std::set_terminate(&my_terminate);
throw "my exception";
}

View File

@ -0,0 +1,26 @@
//
// TEST-OPTIONS: -arch i386 -fexceptions
// TEST-OPTIONS: -arch i386 -fexceptions -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch x86_64
// TEST-OPTIONS: -arch x86_64 -Wl,-no_compact_unwind
// TEST-OPTIONS: -arch ppc -fexceptions
//
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "libunwind.h"
int main()
{
// verify unw_getcontext() returns no UNW_ESUCCESS
unw_context_t uc;
if ( unw_getcontext(&uc) == UNW_ESUCCESS )
return 0;
else
return 1;
}

View File

@ -0,0 +1,46 @@
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include "libunwind.h"
extern int unwind_tester(void*);
extern void* unwind_tester_list[];
int main()
{
// loop over all function pointers in unwind_tester_list
// and call unwind_tester() on each one. If it returns
// non-zero, then that test failed.
void** p;
for(p=unwind_tester_list; *p != NULL; ++p) {
//fprintf(stderr, "unwind_tester(%p)\n", *p);
if ( unwind_tester(*p) )
return 1;
}
return 0;
}
// called by test function
// we unwind through the test function
// and resume at caller (unwind_tester)
void uwind_to_main()
{
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t offset;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
if ( unw_step(&cursor) > 0 ) {
// now in test function
if ( unw_step(&cursor) > 0 ) {
// now in unwind_tester
unw_resume(&cursor);
}
}
// error if we got here
exit(1);
}

502
testsuite/unwind_test_ppc.s Normal file
View File

@ -0,0 +1,502 @@
#
# This is a generic function to test that restoring registers during unwinding work correctly.
#
.literal4
.align 2
LC14: .long 1096810496
LC15: .long 1097859072
LC16: .long 1098907648
LC17: .long 1099431936
LC18: .long 1099956224
LC19: .long 1100480512
LC20: .long 1101004800
LC21: .long 1101529088
LC22: .long 1102053376
LC23: .long 1102577664
LC24: .long 1103101952
LC25: .long 1103626240
LC26: .long 1104150528
LC27: .long 1104674816
LC28: .long 1105199104
LC29: .long 1105723392
LC30: .long 1106247680
LC31: .long 1106771968
.literal16
LV23: .long 0x23232323, 0x23232322, 0x23232321, 0x23232320
LV24: .long 0x24242424, 0x24242422, 0x24242421, 0x24242420
LV25: .long 0x25252525, 0x25252522, 0x25252521, 0x25252520
LV26: .long 0x26262626, 0x26262622, 0x26262621, 0x26262620
LV27: .long 0x27272727, 0x27272722, 0x27272721, 0x27272720
LV28: .long 0x28282828, 0x28282822, 0x28282821, 0x28282820
LV29: .long 0x29292929, 0x29292922, 0x29292921, 0x29292920
LV30: .long 0x30303030, 0x30303022, 0x30303021, 0x30303020
LV31: .long 0x31313131, 0x31313122, 0x31313121, 0x31313120
.text
.globl _unwind_tester
_unwind_tester:
LFB2:
mflr r0
LCFI43:
bl saveFP ; save f14-f31
LCFI44:
stmw r13,-220(r1)
LCFI45:
stwu r1,-336(r1)
LCFI46:
# load magic values into non-volatile registers
lis r31,0x3333
ori r31,r31,0x3131
lis r30,0x3333
ori r30,r30,0x3030
lis r29,0x2222
ori r29,r29,0x2929
lis r28,0x2222
ori r28,r28,0x2828
lis r27,0x2222
ori r27,r27,0x2727
lis r26,0x2222
ori r26,r26,0x2626
lis r25,0x2222
ori r25,r25,0x2525
lis r24,0x2222
ori r24,r24,0x2424
lis r23,0x2222
ori r23,r23,0x2323
lis r22,0x2222
ori r22,r22,0x2222
lis r21,0x2222
ori r21,r21,0x2121
lis r20,0x2222
ori r20,r20,0x2020
lis r19,0x1111
ori r19,r19,0x1919
lis r18,0x1111
ori r18,r18,0x1818
lis r17,0x1111
ori r17,r17,0x1717
lis r16,0x1111
ori r16,r16,0x1616
lis r15,0x1111
ori r15,r15,0x1515
lis r14,0x1111
ori r14,r14,0x1414
lis r13,0x1111
ori r13,r13,0x1313
lis r2,ha16(LC14)
lfs f14,lo16(LC14)(r2)
lis r2,ha16(LC15)
lfs f15,lo16(LC15)(r2)
lis r2,ha16(LC16)
lfs f16,lo16(LC16)(r2)
lis r2,ha16(LC17)
lfs f17,lo16(LC17)(r2)
lis r2,ha16(LC18)
lfs f18,lo16(LC18)(r2)
lis r2,ha16(LC19)
lfs f19,lo16(LC19)(r2)
lis r2,ha16(LC20)
lfs f20,lo16(LC20)(r2)
lis r2,ha16(LC21)
lfs f21,lo16(LC21)(r2)
lis r2,ha16(LC22)
lfs f22,lo16(LC22)(r2)
lis r2,ha16(LC23)
lfs f23,lo16(LC23)(r2)
lis r2,ha16(LC24)
lfs f24,lo16(LC24)(r2)
lis r2,ha16(LC25)
lfs f25,lo16(LC25)(r2)
lis r2,ha16(LC26)
lfs f26,lo16(LC26)(r2)
lis r2,ha16(LC27)
lfs f27,lo16(LC27)(r2)
lis r2,ha16(LC28)
lfs f28,lo16(LC28)(r2)
lis r2,ha16(LC29)
lfs f29,lo16(LC29)(r2)
lis r2,ha16(LC30)
lfs f30,lo16(LC30)(r2)
lis r2,ha16(LC31)
lfs f31,lo16(LC31)(r2)
lis r2,ha16(LV23)
la r2,lo16(LV23)(r2)
lvx v23,0,r2
lis r2,ha16(LV24)
la r2,lo16(LV24)(r2)
lvx v24,0,r2
lis r2,ha16(LV25)
la r2,lo16(LV25)(r2)
lvx v25,0,r2
lis r2,ha16(LV26)
la r2,lo16(LV26)(r2)
lvx v26,0,r2
lis r2,ha16(LV27)
la r2,lo16(LV27)(r2)
lvx v27,0,r2
lis r2,ha16(LV28)
la r2,lo16(LV28)(r2)
lvx v28,0,r2
lis r2,ha16(LV29)
la r2,lo16(LV29)(r2)
lvx v29,0,r2
lis r2,ha16(LV30)
la r2,lo16(LV30)(r2)
lvx v30,0,r2
lis r2,ha16(LV31)
la r2,lo16(LV31)(r2)
lvx v31,0,r2
lis r2,0x1234
ori r2,r2,0x5678
mtocrf 255,r2
# call test function which will invoke unwinder which "returns" here
mtctr r3
bctrl
# verify that non-volatile registers still contain magic values
lis r3,0x3333
ori r3,r3,0x3131
cmpw r3,r31
bne L2
lis r3,0x3333
ori r3,r3,0x3030
cmpw r3,r30
bne L2
lis r3,0x2222
ori r3,r3,0x2929
cmpw r3,r29
bne L2
lis r3,0x2222
ori r3,r3,0x2828
cmpw r3,r28
bne L2
lis r3,0x2222
ori r3,r3,0x2727
cmpw r3,r27
bne L2
lis r3,0x2222
ori r3,r3,0x2626
cmpw r3,r26
bne L2
lis r3,0x2222
ori r3,r3,0x2525
cmpw r3,r25
bne L2
lis r3,0x2222
ori r3,r3,0x2424
cmpw r3,r24
bne L2
lis r3,0x2222
ori r3,r3,0x2323
cmpw r3,r23
bne L2
lis r3,0x2222
ori r3,r3,0x2222
cmpw r3,r22
bne L2
lis r3,0x2222
ori r3,r3,0x2121
cmpw r3,r21
bne L2
lis r3,0x2222
ori r3,r3,0x2020
cmpw r3,r20
bne L2
lis r3,0x1111
ori r3,r3,0x1919
cmpw r3,r19
bne L2
lis r3,0x1111
ori r3,r3,0x1818
cmpw r3,r18
bne L2
lis r3,0x1111
ori r3,r3,0x1717
cmpw r3,r17
bne L2
lis r3,0x1111
ori r3,r3,0x1616
cmpw r3,r16
bne L2
lis r3,0x1111
ori r3,r3,0x1515
cmpw r3,r15
bne L2
lis r3,0x1111
ori r3,r3,0x1414
cmpw r3,r14
bne L2
lis r3,0x1111
ori r3,r3,0x1313
cmpw r3,r13
bne L2
lis r2,ha16(LC14)
lfs f1,lo16(LC14)(r2)
fcmpu cr7,f1,f14
bne cr7,L2
lis r2,ha16(LC15)
lfs f1,lo16(LC15)(r2)
fcmpu cr7,f1,f15
bne cr7,L2
lis r2,ha16(LC16)
lfs f1,lo16(LC16)(r2)
fcmpu cr7,f1,f16
bne cr7,L2
lis r2,ha16(LC17)
lfs f1,lo16(LC17)(r2)
fcmpu cr7,f1,f17
bne cr7,L2
lis r2,ha16(LC18)
lfs f1,lo16(LC18)(r2)
fcmpu cr7,f1,f18
bne cr7,L2
lis r2,ha16(LC19)
lfs f1,lo16(LC19)(r2)
fcmpu cr7,f1,f19
bne cr7,L2
lis r2,ha16(LC20)
lfs f1,lo16(LC20)(r2)
fcmpu cr7,f1,f20
bne cr7,L2
lis r2,ha16(LC21)
lfs f1,lo16(LC21)(r2)
fcmpu cr7,f1,f21
bne cr7,L2
lis r2,ha16(LC22)
lfs f1,lo16(LC22)(r2)
fcmpu cr7,f1,f22
bne cr7,L2
lis r2,ha16(LC23)
lfs f1,lo16(LC23)(r2)
fcmpu cr7,f1,f23
bne cr7,L2
lis r2,ha16(LC24)
lfs f1,lo16(LC24)(r2)
fcmpu cr7,f1,f24
bne cr7,L2
lis r2,ha16(LC25)
lfs f1,lo16(LC25)(r2)
fcmpu cr7,f1,f25
bne cr7,L2
lis r2,ha16(LC26)
lfs f1,lo16(LC26)(r2)
fcmpu cr7,f1,f26
bne cr7,L2
lis r2,ha16(LC27)
lfs f1,lo16(LC27)(r2)
fcmpu cr7,f1,f27
bne cr7,L2
lis r2,ha16(LC28)
lfs f1,lo16(LC28)(r2)
fcmpu cr7,f1,f28
bne cr7,L2
lis r2,ha16(LC29)
lfs f1,lo16(LC29)(r2)
fcmpu cr7,f1,f29
bne cr7,L2
lis r2,ha16(LC30)
lfs f1,lo16(LC30)(r2)
fcmpu cr7,f1,f30
bne cr7,L2
lis r2,ha16(LC31)
lfs f1,lo16(LC31)(r2)
fcmpu cr7,f1,f31
bne cr7,L2
lis r2,ha16(LV23)
la r2,lo16(LV23)(r2)
lvx v1,0,r2
vcmpequw. v0,v1,v23
beq cr6,L2
lis r2,ha16(LV24)
la r2,lo16(LV24)(r2)
lvx v1,0,r2
vcmpequw. v0,v1,v24
beq cr6,L2
lis r2,ha16(LV25)
la r2,lo16(LV25)(r2)
lvx v1,0,r2
vcmpequw. v0,v1,v25
beq cr6,L2
lis r2,ha16(LV26)
la r2,lo16(LV26)(r2)
lvx v1,0,r2
vcmpequw. v0,v1,v26
beq cr6,L2
lis r2,ha16(LV27)
la r2,lo16(LV27)(r2)
lvx v1,0,r2
vcmpequw. v0,v1,v27
beq cr6,L2
lis r2,ha16(LV28)
la r2,lo16(LV28)(r2)
lvx v1,0,r2
vcmpequw. v0,v1,v28
beq cr6,L2
lis r2,ha16(LV29)
la r2,lo16(LV29)(r2)
lvx v1,0,r2
vcmpequw. v0,v1,v29
beq cr6,L2
lis r2,ha16(LV30)
la r2,lo16(LV30)(r2)
lvx v1,0,r2
vcmpequw. v0,v1,v30
beq cr6,L2
lis r2,ha16(LV31)
la r2,lo16(LV31)(r2)
lvx v1,0,r2
vcmpequw. v0,v1,v31
beq cr6,L2
mfcr r3
lis r2,0x00FF
ori r2,r2,0xF000
and r3,r3,r2
lis r2,0x0034
ori r2,r2,0x5000
cmpw r3,r2
bne L2
li r3,0
b L3
L2: li r3,1
L3:
addi r1,r1,336
lwz r0,8(r1)
lmw r13,-220(r1)
mtlr r0
b restFP ; restore f14-f31
LFE2:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 ; Length of Common Information Entry
LSCIE1:
.long 0x0 ; CIE Identifier Tag
.byte 0x1 ; CIE Version
.ascii "zR\0" ; CIE Augmentation
.byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor
.byte 0x7c ; sleb128 -4; CIE Data Alignment Factor
.byte 0x41 ; CIE RA Column
.byte 0x1 ; uleb128 0x1; Augmentation size
.byte 0x10 ; FDE Encoding (pcrel)
.byte 0xc ; DW_CFA_def_cfa
.byte 0x1 ; uleb128 0x1
.byte 0x0 ; uleb128 0x0
.align 2
LECIE1:
.globl _unwind_tester.eh
_unwind_tester.eh:
LSFDE27:
.set L$set$34,LEFDE27-LASFDE27
.long L$set$34 ; FDE Length
LASFDE27:
.long LASFDE27-EH_frame1 ; FDE CIE offset
.long LFB2-. ; FDE initial location
.set L$set$35,LFE2-LFB2
.long L$set$35 ; FDE address range
.byte 0x0 ; uleb128 0x0; Augmentation size
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$36,LCFI43-LFB2
.long L$set$36
.byte 0x9 ; DW_CFA_register
.byte 0x41 ; uleb128 0x41
.byte 0x0 ; uleb128 0x0
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$37,LCFI46-LCFI43
.long L$set$37
.byte 0xe ; DW_CFA_def_cfa_offset
.byte 0xd0,0x2 ; uleb128 0x150
.byte 0x9f ; DW_CFA_offset, column 0x1f
.byte 0x25 ; uleb128 0x25
.byte 0x9e ; DW_CFA_offset, column 0x1e
.byte 0x26 ; uleb128 0x26
.byte 0x9d ; DW_CFA_offset, column 0x1d
.byte 0x27 ; uleb128 0x27
.byte 0x9c ; DW_CFA_offset, column 0x1c
.byte 0x28 ; uleb128 0x28
.byte 0x9b ; DW_CFA_offset, column 0x1b
.byte 0x29 ; uleb128 0x29
.byte 0x9a ; DW_CFA_offset, column 0x1a
.byte 0x2a ; uleb128 0x2a
.byte 0x99 ; DW_CFA_offset, column 0x19
.byte 0x2b ; uleb128 0x2b
.byte 0x98 ; DW_CFA_offset, column 0x18
.byte 0x2c ; uleb128 0x2c
.byte 0x97 ; DW_CFA_offset, column 0x17
.byte 0x2d ; uleb128 0x2d
.byte 0x96 ; DW_CFA_offset, column 0x16
.byte 0x2e ; uleb128 0x2e
.byte 0x95 ; DW_CFA_offset, column 0x15
.byte 0x2f ; uleb128 0x2f
.byte 0x94 ; DW_CFA_offset, column 0x14
.byte 0x30 ; uleb128 0x30
.byte 0x93 ; DW_CFA_offset, column 0x13
.byte 0x31 ; uleb128 0x31
.byte 0x92 ; DW_CFA_offset, column 0x12
.byte 0x32 ; uleb128 0x32
.byte 0x91 ; DW_CFA_offset, column 0x11
.byte 0x33 ; uleb128 0x33
.byte 0x90 ; DW_CFA_offset, column 0x10
.byte 0x34 ; uleb128 0x34
.byte 0x8f ; DW_CFA_offset, column 0xf
.byte 0x35 ; uleb128 0x35
.byte 0x8e ; DW_CFA_offset, column 0xe
.byte 0x36 ; uleb128 0x36
.byte 0x8d ; DW_CFA_offset, column 0xd
.byte 0x37 ; uleb128 0x37
.byte 0x11 ; DW_CFA_offset_extended_sf
.byte 0x41 ; uleb128 0x41
.byte 0x7e ; sleb128 -2
.byte 0xbf ; DW_CFA_offset, column 0x3f
.byte 0x2 ; uleb128 0x2
.byte 0xbe ; DW_CFA_offset, column 0x3e
.byte 0x4 ; uleb128 0x4
.byte 0xbd ; DW_CFA_offset, column 0x3d
.byte 0x6 ; uleb128 0x6
.byte 0xbc ; DW_CFA_offset, column 0x3c
.byte 0x8 ; uleb128 0x8
.byte 0xbb ; DW_CFA_offset, column 0x3b
.byte 0xa ; uleb128 0xa
.byte 0xba ; DW_CFA_offset, column 0x3a
.byte 0xc ; uleb128 0xc
.byte 0xb9 ; DW_CFA_offset, column 0x39
.byte 0xe ; uleb128 0xe
.byte 0xb8 ; DW_CFA_offset, column 0x38
.byte 0x10 ; uleb128 0x10
.byte 0xb7 ; DW_CFA_offset, column 0x37
.byte 0x12 ; uleb128 0x12
.byte 0xb6 ; DW_CFA_offset, column 0x36
.byte 0x14 ; uleb128 0x14
.byte 0xb5 ; DW_CFA_offset, column 0x35
.byte 0x16 ; uleb128 0x16
.byte 0xb4 ; DW_CFA_offset, column 0x34
.byte 0x18 ; uleb128 0x18
.byte 0xb3 ; DW_CFA_offset, column 0x33
.byte 0x1a ; uleb128 0x1a
.byte 0xb2 ; DW_CFA_offset, column 0x32
.byte 0x1c ; uleb128 0x1c
.byte 0xb1 ; DW_CFA_offset, column 0x31
.byte 0x1e ; uleb128 0x1e
.byte 0xb0 ; DW_CFA_offset, column 0x30
.byte 0x20 ; uleb128 0x20
.byte 0xaf ; DW_CFA_offset, column 0x2f
.byte 0x22 ; uleb128 0x22
.byte 0xae ; DW_CFA_offset, column 0x2e
.byte 0x24 ; uleb128 0x24
.align 2
LEFDE27:

View File

@ -0,0 +1,339 @@
# TEST-OPTIONS: unwind_test_main.c unwind_test_ppc.s -arch ppc -fexceptions -faltivec
.data
.globl _unwind_tester_list
_unwind_tester_list:
.long _test_v24_v31
.long _test_r29_r31
.long _test_f26_f31
.long _test_ccr2_ccr4_ctr
.long 0
.text
.align 2
.globl _test_r29_r31
_test_r29_r31:
LFB11:
mflr r0
stmw r29,-12(r1)
stw r0,8(r1)
stwu r1,-80(r1)
LCFI10:
# trash non-volatile registers
li r31,0
li r30,0
li r29,0
# force unwind that should restore non-volatile register
bl _uwind_to_main
addi r1,r1,80
lwz r0,8(r1)
lmw r29,-12(r1)
mtlr r0
blr
LFE11:
.text
.align 2
.globl _test_ccr2_ccr4_ctr
_test_ccr2_ccr4_ctr:
LFB11a:
mflr r0
stw r0,8(r1)
mfcr r0
stw r0,-12(r1)
stw r0,-8(r1)
mfctr r0
stw r0,-4(r1)
stwu r1,-80(r1)
LCFI10a:
# trash non-volatile registers
li r3,0
mtocrf 40,r3
mtctr r3
# force unwind that should restore non-volatile register
bl _uwind_to_main
addi r1,r1,80
lwz r0,-4(r1)
mtctr r0
lwz r0,-8(r1)
mtocrf 4,r0
lwz r0,-12(r1)
mtocrf 128,r0
lwz r0,8(r1)
mtlr r0
blr
LFE11a:
.align 2
.globl _test_f26_f31
_test_f26_f31:
LFB4:
mflr r0
LCFI43:
bl saveFP+48 ; save f26-f31
LCFI44:
stwu r1,-144(r1)
LCFI45:
# trash non-volatile registers
fsub f31,f31,f31
fsub f30,f30,f30
fsub f29,f29,f29
fsub f28,f28,f28
fsub f27,f27,f27
fsub f26,f26,f26
# force unwind that should restore non-volatile register
bl _uwind_to_main
lwz r0,8(r1)
mtlr r0
b restFP+48 ; restore f26-f31
LFE4:
.align 2
.align 2
.globl _test_v24_v31
_test_v24_v31:
LFB3:
mflr r0
stw r0,8(r1)
stwu r1,-352(r1)
LCFI2:
li r0,208
stvx v24,r1,r0
li r0,224
stvx v25,r1,r0
li r0,240
stvx v26,r1,r0
li r0,256
stvx v27,r1,r0
li r0,272
stvx v28,r1,r0
li r0,288
stvx v29,r1,r0
li r0,304
stvx v30,r1,r0
li r0,320
stvx v31,r1,r0
LCFI11:
mfspr r0,256
stw r0,348(r1)
oris r0,r0,0x3ff0
ori r0,r0,255
mtspr 256,r0
# trash non-volatile registers
vor v24,v20,v20
vor v25,v20,v20
vor v26,v20,v20
vor v27,v20,v20
vor v28,v20,v20
vor v29,v20,v20
vor v30,v20,v20
vor v31,v20,v20
# force unwind that should restore non-volatile register
bl _uwind_to_main
li r0,208
lwz r12,348(r1)
lvx v24,r1,r0
li r0,224
lvx v25,r1,r0
li r0,240
lvx v26,r1,r0
li r0,256
lvx v27,r1,r0
li r0,272
lvx v28,r1,r0
li r0,288
lvx v29,r1,r0
li r0,304
lvx v30,r1,r0
li r0,320
lvx v31,r1,r0
mtspr 256,r12
addi r1,r1,352
lwz r0,8(r1)
mtlr r0
blr
LFE3:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 ; Length of Common Information Entry
LSCIE1:
.long 0x0 ; CIE Identifier Tag
.byte 0x1 ; CIE Version
.ascii "zR\0" ; CIE Augmentation
.byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor
.byte 0x7c ; sleb128 -4; CIE Data Alignment Factor
.byte 0x41 ; CIE RA Column
.byte 0x1 ; uleb128 0x1; Augmentation size
.byte 0x10 ; FDE Encoding (pcrel)
.byte 0xc ; DW_CFA_def_cfa
.byte 0x1 ; uleb128 0x1
.byte 0x0 ; uleb128 0x0
.align 2
LECIE1:
.globl _test_r29_r31.eh
_test_r29_r31.eh:
LSFDE9:
.set L$set$7,LEFDE9-LASFDE9
.long L$set$7 ; FDE Length
LASFDE9:
.long LASFDE9-EH_frame1 ; FDE CIE offset
.long LFB11-. ; FDE initial location
.set L$set$8,LFE11-LFB11
.long L$set$8 ; FDE address range
.byte 0x0 ; uleb128 0x0; Augmentation size
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$9,LCFI10-LFB11
.long L$set$9
.byte 0xe ; DW_CFA_def_cfa_offset
.byte 0x50 ; uleb128 0x50
.byte 0x9f ; DW_CFA_offset, column 0x1f
.byte 0x1 ; uleb128 0x1
.byte 0x9e ; DW_CFA_offset, column 0x1e
.byte 0x2 ; uleb128 0x2
.byte 0x9d ; DW_CFA_offset, column 0x1d
.byte 0x3 ; uleb128 0x3
.byte 0x11 ; DW_CFA_offset_extended_sf
.byte 0x41 ; uleb128 0x41
.byte 0x7e ; sleb128 -2
.align 2
LEFDE9:
.globl _test_ccr2_ccr4_ctr.eh
_test_ccr2_ccr4_ctr.eh:
LSFDE9a:
.set L$set$7,LEFDE9a-LASFDE9a
.long L$set$7 ; FDE Length
LASFDE9a:
.long LASFDE9a-EH_frame1 ; FDE CIE offset
.long LFB11a-. ; FDE initial location
.set L$set$8,LFE11a-LFB11a
.long L$set$8 ; FDE address range
.byte 0x0 ; uleb128 0x0; Augmentation size
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$9,LCFI10a-LFB11a
.long L$set$9
.byte 0xe ; DW_CFA_def_cfa_offset
.byte 0x50 ; uleb128 0x50
.byte 0x11 ; DW_CFA_offset_extended_sf
.byte 0x42 ; uleb128 0x42
.byte 0x01 ; sleb128 1
.byte 0x11 ; DW_CFA_offset_extended_sf
.byte 0x48 ; uleb128 0x48
.byte 0x02 ; sleb128 2
.byte 0x11 ; DW_CFA_offset_extended_sf
.byte 0x46 ; uleb128 0x46
.byte 0x03 ; sleb128 3
.byte 0x11 ; DW_CFA_offset_extended_sf
.byte 0x41 ; uleb128 0x41
.byte 0x7e ; sleb128 -2
.align 2
LEFDE9a:
.globl _test_f26_f31
_test_f26_f31.eh:
LSFDE29:
.set L$set$34,LEFDE29-LASFDE29
.long L$set$34 ; FDE Length
LASFDE29:
.long LASFDE29-EH_frame1 ; FDE CIE offset
.long LFB4-. ; FDE initial location
.set L$set$35,LFE4-LFB4
.long L$set$35 ; FDE address range
.byte 0x0 ; uleb128 0x0; Augmentation size
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$36,LCFI43-LFB4
.long L$set$36
.byte 0x9 ; DW_CFA_register
.byte 0x41 ; uleb128 0x41
.byte 0x0 ; uleb128 0x0
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$37,LCFI45-LCFI43
.long L$set$37
.byte 0xe ; DW_CFA_def_cfa_offset
.byte 0x90,0x1 ; uleb128 0x90
.byte 0x11 ; DW_CFA_offset_extended_sf
.byte 0x41 ; uleb128 0x41
.byte 0x7e ; sleb128 -2
.byte 0xbf ; DW_CFA_offset, column 0x3f
.byte 0x2 ; uleb128 0x2
.byte 0xbe ; DW_CFA_offset, column 0x3e
.byte 0x4 ; uleb128 0x4
.byte 0xbd ; DW_CFA_offset, column 0x3d
.byte 0x6 ; uleb128 0x6
.byte 0xbc ; DW_CFA_offset, column 0x3c
.byte 0x8 ; uleb128 0x8
.byte 0xbb ; DW_CFA_offset, column 0x3b
.byte 0xa ; uleb128 0xa
.byte 0xba ; DW_CFA_offset, column 0x3a
.byte 0xc ; uleb128 0xc
.align 2
LEFDE29:
.globl _test_v24_v31.eh
_test_v24_v31.eh:
LSFDE3:
.set L$set$1,LEFDE3-LASFDE3
.long L$set$1 ; FDE Length
LASFDE3:
.long LASFDE3-EH_frame1 ; FDE CIE offset
.long LFB3-. ; FDE initial location
.set L$set$2,LFE3-LFB3
.long L$set$2 ; FDE address range
.byte 0x0 ; uleb128 0x0; Augmentation size
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$3,LCFI2-LFB3
.long L$set$3
.byte 0xe ; DW_CFA_def_cfa_offset
.byte 0xe0,0x2 ; uleb128 0x160
.byte 0x4 ; DW_CFA_advance_loc4
.set L$set$4,LCFI11-LCFI2
.long L$set$4
.byte 0x5 ; DW_CFA_offset_extended
.byte 0x6c ; uleb128 0x6c
.byte 0x8 ; uleb128 0x8
.byte 0x5 ; DW_CFA_offset_extended
.byte 0x6b ; uleb128 0x6b
.byte 0xc ; uleb128 0xc
.byte 0x5 ; DW_CFA_offset_extended
.byte 0x6a ; uleb128 0x6a
.byte 0x10 ; uleb128 0x10
.byte 0x5 ; DW_CFA_offset_extended
.byte 0x69 ; uleb128 0x69
.byte 0x14 ; uleb128 0x14
.byte 0x5 ; DW_CFA_offset_extended
.byte 0x68 ; uleb128 0x68
.byte 0x18 ; uleb128 0x18
.byte 0x5 ; DW_CFA_offset_extended
.byte 0x67 ; uleb128 0x67
.byte 0x1c ; uleb128 0x1c
.byte 0x5 ; DW_CFA_offset_extended
.byte 0x66 ; uleb128 0x66
.byte 0x20 ; uleb128 0x20
.byte 0x5 ; DW_CFA_offset_extended
.byte 0x65 ; uleb128 0x65
.byte 0x24 ; uleb128 0x24
.byte 0x11 ; DW_CFA_offset_extended_sf
.byte 0x41 ; uleb128 0x41
.byte 0x7e ; sleb128 -2
.align 2
LEFDE3:

104
testsuite/unwind_test_x86.s Normal file
View File

@ -0,0 +1,104 @@
#
# This is a generic function to test that restoring registers during unwinding work correctly.
#
.text
.globl _unwind_tester
_unwind_tester:
LFB2:
pushl %ebp
LCFI0:
movl %esp, %ebp
LCFI1:
subl $56, %esp
LCFI2:
movl %ebx, -12(%ebp)
LCFI3:
movl %esi, -8(%ebp)
LCFI4:
movl %edi, -4(%ebp)
LCFI5:
# load magic values into non-volatile registers
movl $0x12344321, %ebx
movl $0x56788765, %esi
movl $0xABCDDCBA, %edi
# call test function which will invoke unwinder which "returns" here
call *8(%ebp)
# verify that non-volatile registers still contain magic values
cmpl $0x12344321, %ebx
jne L2
cmpl $0x56788765, %esi
jne L2
cmpl $0xABCDDCBA, %edi
jne L2
movl $0, %eax
jmp L3
L2: movl $1, %eax
L3:
movl -12(%ebp), %ebx
movl -8(%ebp), %esi
movl -4(%ebp), %edi
leave
ret
LFE2:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 # Length of Common Information Entry
LSCIE1:
.long 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
.byte 0x7c # sleb128 -4; CIE Data Alignment Factor
.byte 0x8 # CIE RA Column
.byte 0x1 # uleb128 0x1; Augmentation size
.byte 0x10 # FDE Encoding (pcrel)
.byte 0xc # DW_CFA_def_cfa
.byte 0x5 # uleb128 0x5
.byte 0x4 # uleb128 0x4
.byte 0x88 # DW_CFA_offset, column 0x8
.byte 0x1 # uleb128 0x1
.align 2
LECIE1:
.globl _unwind_tester.eh
_unwind_tester.eh:
LSFDE1:
.set L$set$1,LEFDE1-LASFDE1
.long L$set$1 # FDE Length
LASFDE1:
.long LASFDE1-EH_frame1 # FDE CIE offset
.long LFB2-. # FDE initial location
.set L$set$2,LFE2-LFB2
.long L$set$2 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$3,LCFI0-LFB2
.long L$set$3
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$4,LCFI1-LCFI0
.long L$set$4
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$5,LCFI5-LCFI1
.long L$set$5
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x5 # uleb128 0x5
.align 2
LEFDE1:

View File

@ -0,0 +1,125 @@
#
# This is a generic function to test that restoring registers during unwinding work correctly.
#
.text
.globl _unwind_tester
_unwind_tester:
LFB3:
pushq %rbp
LCFI45:
movq %rsp, %rbp
LCFI46:
movq %rbx, -40(%rbp)
LCFI47:
movq %r12, -32(%rbp)
LCFI48:
movq %r13, -24(%rbp)
LCFI49:
movq %r14, -16(%rbp)
LCFI50:
movq %r15, -8(%rbp)
LCFI51:
subq $48, %rsp
LCFI52:
# load magic values into non-volatile registers
movq $0x1234567887654321, %rbx
movq $0x02468ACEECA86420, %r12
movq $0x13579BDFFDB97531, %r13
movq $0x1122334455667788, %r14
movq $0x0022446688AACCEE, %r15
# call test function which will invoke unwinder which "returns" here
call *%rdi
# verify that non-volatile registers still contain magic values
movq $0x1234567887654321, %rax
cmpq %rax, %rbx
jne L2
movq $0x02468ACEECA86420, %rax
cmpq %rax, %r12
jne L2
movq $0x13579BDFFDB97531, %rax
cmpq %rax, %r13
jne L2
movq $0x1122334455667788, %rax
cmpq %rax, %r14
jne L2
movq $0x0022446688AACCEE, %rax
cmpq %rax, %r15
jne L2
movl $0, %eax
jmp L3
L2: movl $1, %eax
L3:
movq -40(%rbp), %rbx
movq -32(%rbp), %r12
movq -24(%rbp), %r13
movq -16(%rbp), %r14
movq -8(%rbp), %r15
leave
ret
LFE3:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 # Length of Common Information Entry
LSCIE1:
.long 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
.byte 0x78 # sleb128 -8; CIE Data Alignment Factor
.byte 0x10 # CIE RA Column
.byte 0x1 # uleb128 0x1; Augmentation size
.byte 0x10 # FDE Encoding (pcrel)
.byte 0xc # DW_CFA_def_cfa
.byte 0x7 # uleb128 0x7
.byte 0x8 # uleb128 0x8
.byte 0x90 # DW_CFA_offset, column 0x10
.byte 0x1 # uleb128 0x1
.align 3
LECIE1:
.globl _unwind_tester.eh
_unwind_tester.eh:
LSFDE23:
.set L$set$52,LEFDE23-LASFDE23
.long L$set$52 # FDE Length
LASFDE23:
.long LASFDE23-EH_frame1 # FDE CIE offset
.quad LFB3-. # FDE initial location
.set L$set$53,LFE3-LFB3
.quad L$set$53 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$54,LCFI45-LFB3
.long L$set$54
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x10 # uleb128 0x10
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$55,LCFI46-LCFI45
.long L$set$55
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x6 # uleb128 0x6
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$56,LCFI52-LCFI46
.long L$set$56
.byte 0x8f # DW_CFA_offset, column 0xf
.byte 0x3 # uleb128 0x3
.byte 0x8e # DW_CFA_offset, column 0xe
.byte 0x4 # uleb128 0x4
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x5 # uleb128 0x5
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x6 # uleb128 0x6
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x7 # uleb128 0x7
.align 3
LEFDE23:

View File

@ -0,0 +1,599 @@
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64
.data
.globl _unwind_tester_list
_unwind_tester_list:
.quad _test_no_reg
.quad _test_rbx
.quad _test_rbx_r12
.quad _test_rbx_r14
.quad _test_rbx_r12_r13
.quad _test_rbx_r12_r13_r14
.quad _test_r14_r13_r12_rbx
.quad _test_rbx_r12_r13_r14_r15
.quad _test_r13_rbx_r14_r15_r12
.quad 0
.text
LFE14:
.globl _test_no_reg
_test_no_reg:
LFB13:
pushq %rbp
LCFI2:
movq %rsp, %rbp
LCFI3:
call _uwind_to_main
leave
ret
LFE13:
.globl _test_rbx
_test_rbx:
LFB10:
pushq %rbp
LCFI8:
movq %rsp, %rbp
LCFI9:
pushq %rbx
LCFI10:
subq $8, %rsp
LCFI11:
movq $0, %rbx
call _uwind_to_main
addq $8, %rsp
popq %rbx
leave
ret
LFE10:
.globl _test_rbx_r12
_test_rbx_r12:
LFB8:
pushq %rbp
LCFI16:
movq %rsp, %rbp
LCFI17:
movq %rbx, -16(%rbp)
LCFI18:
movq %r12, -8(%rbp)
LCFI19:
subq $16, %rsp
LCFI20:
movq $0, %rbx
movq $0, %r12
call _uwind_to_main
movq (%rsp), %rbx
movq 8(%rsp), %r12
leave
ret
LFE8:
.globl _test_rbx_r14
_test_rbx_r14:
LFB8a:
pushq %rbp
LCFI16a:
movq %rsp, %rbp
LCFI17a:
movq %rbx, -16(%rbp)
LCFI18a:
movq %r14, -8(%rbp)
LCFI19a:
subq $16, %rsp
LCFI20a:
movq $0, %rbx
movq $0, %r14
call _uwind_to_main
movq (%rsp), %rbx
movq 8(%rsp), %r14
leave
ret
LFE8a:
.globl _test_rbx_r12_r13
_test_rbx_r12_r13:
LFB6:
pushq %rbp
LCFI26:
movq %rsp, %rbp
LCFI27:
movq %rbx, -24(%rbp)
LCFI28:
movq %r12, -16(%rbp)
LCFI29:
movq %r13, -8(%rbp)
LCFI30:
subq $32, %rsp
LCFI31:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
call _uwind_to_main
movq -24(%rbp), %rbx
movq -16(%rbp), %r12
movq -8(%rbp), %r13
leave
ret
LFE6:
.globl _test_rbx_r12_r13_r14
_test_rbx_r12_r13_r14:
LFB4:
pushq %rbp
LCFI38:
movq %rsp, %rbp
LCFI39:
movq %rbx, -32(%rbp)
LCFI40:
movq %r12, -24(%rbp)
LCFI41:
movq %r13, -16(%rbp)
LCFI42:
movq %r14, -8(%rbp)
LCFI43:
subq $32, %rsp
LCFI44:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
movq $0, %r14
call _uwind_to_main
movq (%rsp), %rbx
movq 8(%rsp), %r12
movq 16(%rsp), %r13
movq 24(%rsp), %r14
leave
ret
LFE4:
.globl _test_r14_r13_r12_rbx
_test_r14_r13_r12_rbx:
LFB4a:
pushq %rbp
LCFI38a:
movq %rsp, %rbp
LCFI39a:
movq %r14, -32(%rbp)
LCFI40a:
movq %r13, -24(%rbp)
LCFI41a:
movq %r12, -16(%rbp)
LCFI42a:
movq %rbx, -8(%rbp)
LCFI43a:
subq $32, %rsp
LCFI44a:
movq $0, %r14
movq $0, %r13
movq $0, %r12
movq $0, %rbx
call _uwind_to_main
movq -32(%rbp), %r14
movq -24(%rbp), %r13
movq -16(%rbp), %r12
movq -8(%rbp), %rbx
leave
ret
LFE4a:
.globl _test_rbx_r12_r13_r14_r15
_test_rbx_r12_r13_r14_r15:
LFB3:
pushq %rbp
LCFI45:
movq %rsp, %rbp
LCFI46:
movq %rbx, -40(%rbp)
LCFI47:
movq %r12, -32(%rbp)
LCFI48:
movq %r13, -24(%rbp)
LCFI49:
movq %r14, -16(%rbp)
LCFI50:
movq %r15, -8(%rbp)
LCFI51:
subq $48, %rsp
LCFI52:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
movq $0, %r14
call _uwind_to_main
movq -40(%rbp), %rbx
movq -32(%rbp), %r12
movq -24(%rbp), %r13
movq -16(%rbp), %r14
movq -8(%rbp), %r15
leave
ret
LFE3:
.globl _test_r13_rbx_r14_r15_r12
_test_r13_rbx_r14_r15_r12:
LFB3a:
pushq %rbp
LCFI45a:
movq %rsp, %rbp
LCFI46a:
movq %r13, -40(%rbp)
LCFI47a:
movq %rbx, -32(%rbp)
LCFI48a:
movq %r14, -24(%rbp)
LCFI49a:
movq %r15, -16(%rbp)
LCFI50a:
movq %r12, -8(%rbp)
LCFI51a:
subq $48, %rsp
LCFI52a:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
movq $0, %r14
movq $0, %r15
call _uwind_to_main
movq -40(%rbp), %r13
movq -32(%rbp), %rbx
movq -24(%rbp), %r14
movq -16(%rbp), %r15
movq -8(%rbp), %r12
leave
ret
LFE3a:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0
LSCIE1:
.long 0x0
.byte 0x1
.ascii "zR\0"
.byte 0x1
.byte 0x78
.byte 0x10
.byte 0x1
.byte 0x10
.byte 0xc
.byte 0x7
.byte 0x8
.byte 0x90 // DW_CFA_offset(ret_addr, -8)
.byte 0x1
.byte 0x90 // DW_CFA_offset(ret_addr, -8)
.byte 0x1 // this repeat is idiom that means don't create compact unwind info
.align 3
LECIE1:
.globl _test_no_reg.eh
_test_no_reg.eh:
LSFDE3:
.set L$set$5,LEFDE3-LASFDE3
.long L$set$5
LASFDE3:
.long LASFDE3-EH_frame1
.quad LFB13-.
.set L$set$6,LFE13-LFB13
.quad L$set$6
.byte 0x0
.byte 0x4
.set L$set$7,LCFI2-LFB13
.long L$set$7
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$8,LCFI3-LCFI2
.long L$set$8
.byte 0xd
.byte 0x6
.align 3
LEFDE3:
.globl _test_rbx.eh
_test_rbx.eh:
LSFDE9:
.set L$set$17,LEFDE9-LASFDE9
.long L$set$17
LASFDE9:
.long LASFDE9-EH_frame1
.quad LFB10-.
.set L$set$18,LFE10-LFB10
.quad L$set$18
.byte 0x0
.byte 0x4
.set L$set$19,LCFI8-LFB10
.long L$set$19
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$20,LCFI9-LCFI8
.long L$set$20
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$21,LCFI11-LCFI9
.long L$set$21
.byte 0x83
.byte 0x3
.align 3
LEFDE9:
.globl _test_rbx_r12.eh
_test_rbx_r12.eh:
LSFDE13:
.set L$set$27,LEFDE13-LASFDE13
.long L$set$27
LASFDE13:
.long LASFDE13-EH_frame1
.quad LFB8-.
.set L$set$28,LFE8-LFB8
.quad L$set$28
.byte 0x0
.byte 0x4
.set L$set$29,LCFI16-LFB8
.long L$set$29
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$30,LCFI17-LCFI16
.long L$set$30
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$31,LCFI20-LCFI17
.long L$set$31
.byte 0x8c
.byte 0x3
.byte 0x83
.byte 0x4
.align 3
LEFDE13:
.globl _test_rbx_r14.eh
_test_rbx_r14.eh:
LSFDE13a:
.set L$set$27a,LEFDE13a-LASFDE13a
.long L$set$27a
LASFDE13a:
.long LASFDE13a-EH_frame1
.quad LFB8a-.
.set L$set$28a,LFE8a-LFB8a
.quad L$set$28a
.byte 0x0
.byte 0x4
.set L$set$29a,LCFI16a-LFB8a
.long L$set$29a
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$30a,LCFI17a-LCFI16a
.long L$set$30a
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$31a,LCFI20a-LCFI17a
.long L$set$31a
.byte 0x8e
.byte 0x3
.byte 0x83
.byte 0x4
.align 3
LEFDE13a:
.globl _test_rbx_r12_r13.eh
_test_rbx_r12_r13.eh:
LSFDE17:
.set L$set$37,LEFDE17-LASFDE17
.long L$set$37
LASFDE17:
.long LASFDE17-EH_frame1
.quad LFB6-.
.set L$set$38,LFE6-LFB6
.quad L$set$38
.byte 0x0
.byte 0x4
.set L$set$39,LCFI26-LFB6
.long L$set$39
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$40,LCFI27-LCFI26
.long L$set$40
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$41,LCFI31-LCFI27
.long L$set$41
.byte 0x8d
.byte 0x3
.byte 0x8c
.byte 0x4
.byte 0x83
.byte 0x5
.align 3
LEFDE17:
.globl _test_rbx_r12_r13_r14.eh
_test_rbx_r12_r13_r14.eh:
LSFDE21:
.set L$set$47,LEFDE21-LASFDE21
.long L$set$47
LASFDE21:
.long LASFDE21-EH_frame1
.quad LFB4-.
.set L$set$48,LFE4-LFB4
.quad L$set$48
.byte 0x0
.byte 0x4
.set L$set$49,LCFI38-LFB4
.long L$set$49
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$50,LCFI39-LCFI38
.long L$set$50
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$51,LCFI44-LCFI39
.long L$set$51
.byte 0x8e
.byte 0x3
.byte 0x8d
.byte 0x4
.byte 0x8c
.byte 0x5
.byte 0x83
.byte 0x6
.align 3
LEFDE21:
.globl _test_r14_r13_r12_rbx.eh
_test_r14_r13_r12_rbx.eh:
LSFDE21a:
.set L$set$47a,LEFDE21a-LASFDE21a
.long L$set$47a
LASFDE21a:
.long LASFDE21a-EH_frame1
.quad LFB4a-.
.set L$set$48a,LFE4a-LFB4a
.quad L$set$48a
.byte 0x0
.byte 0x4
.set L$set$49a,LCFI38a-LFB4a
.long L$set$49a
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$50a,LCFI39a-LCFI38a
.long L$set$50a
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$51a,LCFI44a-LCFI39a
.long L$set$51a
.byte 0x8e
.byte 0x6
.byte 0x8d
.byte 0x5
.byte 0x8c
.byte 0x4
.byte 0x83
.byte 0x3
.align 3
LEFDE21a:
.globl _test_rbx_r12_r13_r14_r15.eh
_test_rbx_r12_r13_r14_r15.eh:
LSFDE23:
.set L$set$52,LEFDE23-LASFDE23
.long L$set$52
LASFDE23:
.long LASFDE23-EH_frame1
.quad LFB3-.
.set L$set$53,LFE3-LFB3
.quad L$set$53
.byte 0x0
.byte 0x4
.set L$set$54,LCFI45-LFB3
.long L$set$54
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$55,LCFI46-LCFI45
.long L$set$55
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$56,LCFI52-LCFI46
.long L$set$56
.byte 0x8f
.byte 0x3
.byte 0x8e
.byte 0x4
.byte 0x8d
.byte 0x5
.byte 0x8c
.byte 0x6
.byte 0x83
.byte 0x7
.align 3
LEFDE23:
.globl _test_r13_rbx_r14_r15_r12.eh
_test_r13_rbx_r14_r15_r12.eh:
LSFDE23a:
.set L$set$52a,LEFDE23a-LASFDE23a
.long L$set$52a
LASFDE23a:
.long LASFDE23a-EH_frame1
.quad LFB3a-.
.set L$set$53a,LFE3a-LFB3a
.quad L$set$53a
.byte 0x0
.byte 0x4
.set L$set$54a,LCFI45a-LFB3a
.long L$set$54a
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$55a,LCFI46a-LCFI45a
.long L$set$55a
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$56a,LCFI52a-LCFI46a
.long L$set$56a
.byte 0x8c
.byte 0x3
.byte 0x8f
.byte 0x4
.byte 0x8e
.byte 0x5
.byte 0x83
.byte 0x6
.byte 0x8d
.byte 0x7
.align 3
LEFDE23a:
.subsections_via_symbols

View File

@ -0,0 +1,674 @@
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -DUSE_COMPACT_UNWIND=1
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -DUSE_EH_FRAME=1
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -DUSE_COMPACT_UNWIND=1 -DUSE_EH_FRAME=1
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -DUSE_EH_FRAME=1 -Wl,-no_compact_unwind
.data
.globl _unwind_tester_list
_unwind_tester_list:
.quad _test_no_reg
.quad _test_rbx
.quad _test_rbx_r12
.quad _test_rbx_r14
.quad _test_rbx_r12_r13
.quad _test_rbx_r12_r13_r14
.quad _test_r14_r13_r12_rbx
.quad _test_rbx_r12_r13_r14_r15
.quad _test_r13_rbx_r14_r15_r12
.quad 0
.text
LFE14:
.globl _test_no_reg
_test_no_reg:
LFB13:
pushq %rbp
LCFI2:
movq %rsp, %rbp
LCFI3:
call _uwind_to_main
leave
ret
LFE13:
.globl _test_rbx
_test_rbx:
LFB10:
pushq %rbp
LCFI8:
movq %rsp, %rbp
LCFI9:
pushq %rbx
LCFI10:
subq $8, %rsp
LCFI11:
movq $0, %rbx
call _uwind_to_main
addq $8, %rsp
popq %rbx
leave
ret
LFE10:
.globl _test_rbx_r12
_test_rbx_r12:
LFB8:
pushq %rbp
LCFI16:
movq %rsp, %rbp
LCFI17:
movq %rbx, -16(%rbp)
LCFI18:
movq %r12, -8(%rbp)
LCFI19:
subq $16, %rsp
LCFI20:
movq $0, %rbx
movq $0, %r12
call _uwind_to_main
movq (%rsp), %rbx
movq 8(%rsp), %r12
leave
ret
LFE8:
.globl _test_rbx_r14
_test_rbx_r14:
LFB8a:
pushq %rbp
LCFI16a:
movq %rsp, %rbp
LCFI17a:
movq %rbx, -16(%rbp)
LCFI18a:
movq %r14, -8(%rbp)
LCFI19a:
subq $16, %rsp
LCFI20a:
movq $0, %rbx
movq $0, %r14
call _uwind_to_main
movq (%rsp), %rbx
movq 8(%rsp), %r14
leave
ret
LFE8a:
.globl _test_rbx_r12_r13
_test_rbx_r12_r13:
LFB6:
pushq %rbp
LCFI26:
movq %rsp, %rbp
LCFI27:
movq %rbx, -24(%rbp)
LCFI28:
movq %r12, -16(%rbp)
LCFI29:
movq %r13, -8(%rbp)
LCFI30:
subq $32, %rsp
LCFI31:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
call _uwind_to_main
movq -24(%rbp), %rbx
movq -16(%rbp), %r12
movq -8(%rbp), %r13
leave
ret
LFE6:
.globl _test_rbx_r12_r13_r14
_test_rbx_r12_r13_r14:
LFB4:
pushq %rbp
LCFI38:
movq %rsp, %rbp
LCFI39:
movq %rbx, -32(%rbp)
LCFI40:
movq %r12, -24(%rbp)
LCFI41:
movq %r13, -16(%rbp)
LCFI42:
movq %r14, -8(%rbp)
LCFI43:
subq $32, %rsp
LCFI44:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
movq $0, %r14
call _uwind_to_main
movq (%rsp), %rbx
movq 8(%rsp), %r12
movq 16(%rsp), %r13
movq 24(%rsp), %r14
leave
ret
LFE4:
.globl _test_r14_r13_r12_rbx
_test_r14_r13_r12_rbx:
LFB4a:
pushq %rbp
LCFI38a:
movq %rsp, %rbp
LCFI39a:
movq %r14, -32(%rbp)
LCFI40a:
movq %r13, -24(%rbp)
LCFI41a:
movq %r12, -16(%rbp)
LCFI42a:
movq %rbx, -8(%rbp)
LCFI43a:
subq $32, %rsp
LCFI44a:
movq $0, %r14
movq $0, %r13
movq $0, %r12
movq $0, %rbx
call _uwind_to_main
movq -32(%rbp), %r14
movq -24(%rbp), %r13
movq -16(%rbp), %r12
movq -8(%rbp), %rbx
leave
ret
LFE4a:
.globl _test_rbx_r12_r13_r14_r15
_test_rbx_r12_r13_r14_r15:
LFB3:
pushq %rbp
LCFI45:
movq %rsp, %rbp
LCFI46:
movq %rbx, -40(%rbp)
LCFI47:
movq %r12, -32(%rbp)
LCFI48:
movq %r13, -24(%rbp)
LCFI49:
movq %r14, -16(%rbp)
LCFI50:
movq %r15, -8(%rbp)
LCFI51:
subq $48, %rsp
LCFI52:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
movq $0, %r14
call _uwind_to_main
movq -40(%rbp), %rbx
movq -32(%rbp), %r12
movq -24(%rbp), %r13
movq -16(%rbp), %r14
movq -8(%rbp), %r15
leave
ret
LFE3:
.globl _test_r13_rbx_r14_r15_r12
_test_r13_rbx_r14_r15_r12:
LFB3a:
pushq %rbp
LCFI45a:
movq %rsp, %rbp
LCFI46a:
movq %r13, -40(%rbp)
LCFI47a:
movq %rbx, -32(%rbp)
LCFI48a:
movq %r14, -24(%rbp)
LCFI49a:
movq %r15, -16(%rbp)
LCFI50a:
movq %r12, -8(%rbp)
LCFI51a:
subq $48, %rsp
LCFI52a:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
movq $0, %r14
movq $0, %r15
call _uwind_to_main
movq -40(%rbp), %r13
movq -32(%rbp), %rbx
movq -24(%rbp), %r14
movq -16(%rbp), %r15
movq -8(%rbp), %r12
leave
ret
LFE3a:
#if USE_EH_FRAME
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0
LSCIE1:
.long 0x0
.byte 0x1
.ascii "zR\0"
.byte 0x1
.byte 0x78
.byte 0x10
.byte 0x1
.byte 0x10
.byte 0xc
.byte 0x7
.byte 0x8
.byte 0x90
.byte 0x1
.align 3
LECIE1:
.globl _test_no_reg.eh
_test_no_reg.eh:
LSFDE3:
.set L$set$5,LEFDE3-LASFDE3
.long L$set$5
LASFDE3:
.long LASFDE3-EH_frame1
.quad LFB13-.
.set L$set$6,LFE13-LFB13
.quad L$set$6
.byte 0x0
.byte 0x4
.set L$set$7,LCFI2-LFB13
.long L$set$7
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$8,LCFI3-LCFI2
.long L$set$8
.byte 0xd
.byte 0x6
.align 3
LEFDE3:
.globl _test_rbx.eh
_test_rbx.eh:
LSFDE9:
.set L$set$17,LEFDE9-LASFDE9
.long L$set$17
LASFDE9:
.long LASFDE9-EH_frame1
.quad LFB10-.
.set L$set$18,LFE10-LFB10
.quad L$set$18
.byte 0x0
.byte 0x4
.set L$set$19,LCFI8-LFB10
.long L$set$19
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$20,LCFI9-LCFI8
.long L$set$20
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$21,LCFI11-LCFI9
.long L$set$21
.byte 0x83
.byte 0x3
.align 3
LEFDE9:
.globl _test_rbx_r12.eh
_test_rbx_r12.eh:
LSFDE13:
.set L$set$27,LEFDE13-LASFDE13
.long L$set$27
LASFDE13:
.long LASFDE13-EH_frame1
.quad LFB8-.
.set L$set$28,LFE8-LFB8
.quad L$set$28
.byte 0x0
.byte 0x4
.set L$set$29,LCFI16-LFB8
.long L$set$29
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$30,LCFI17-LCFI16
.long L$set$30
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$31,LCFI20-LCFI17
.long L$set$31
.byte 0x8c
.byte 0x3
.byte 0x83
.byte 0x4
.align 3
LEFDE13:
.globl _test_rbx_r14.eh
_test_rbx_r14.eh:
LSFDE13a:
.set L$set$27a,LEFDE13a-LASFDE13a
.long L$set$27a
LASFDE13a:
.long LASFDE13a-EH_frame1
.quad LFB8a-.
.set L$set$28a,LFE8a-LFB8a
.quad L$set$28a
.byte 0x0
.byte 0x4
.set L$set$29a,LCFI16a-LFB8a
.long L$set$29a
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$30a,LCFI17a-LCFI16a
.long L$set$30a
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$31a,LCFI20a-LCFI17a
.long L$set$31a
.byte 0x8e
.byte 0x3
.byte 0x83
.byte 0x4
.align 3
LEFDE13a:
.globl _test_rbx_r12_r13.eh
_test_rbx_r12_r13.eh:
LSFDE17:
.set L$set$37,LEFDE17-LASFDE17
.long L$set$37
LASFDE17:
.long LASFDE17-EH_frame1
.quad LFB6-.
.set L$set$38,LFE6-LFB6
.quad L$set$38
.byte 0x0
.byte 0x4
.set L$set$39,LCFI26-LFB6
.long L$set$39
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$40,LCFI27-LCFI26
.long L$set$40
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$41,LCFI31-LCFI27
.long L$set$41
.byte 0x8d
.byte 0x3
.byte 0x8c
.byte 0x4
.byte 0x83
.byte 0x5
.align 3
LEFDE17:
.globl _test_rbx_r12_r13_r14.eh
_test_rbx_r12_r13_r14.eh:
LSFDE21:
.set L$set$47,LEFDE21-LASFDE21
.long L$set$47
LASFDE21:
.long LASFDE21-EH_frame1
.quad LFB4-.
.set L$set$48,LFE4-LFB4
.quad L$set$48
.byte 0x0
.byte 0x4
.set L$set$49,LCFI38-LFB4
.long L$set$49
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$50,LCFI39-LCFI38
.long L$set$50
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$51,LCFI44-LCFI39
.long L$set$51
.byte 0x8e
.byte 0x3
.byte 0x8d
.byte 0x4
.byte 0x8c
.byte 0x5
.byte 0x83
.byte 0x6
.align 3
LEFDE21:
.globl _test_r14_r13_r12_rbx.eh
_test_r14_r13_r12_rbx.eh:
LSFDE21a:
.set L$set$47a,LEFDE21a-LASFDE21a
.long L$set$47a
LASFDE21a:
.long LASFDE21a-EH_frame1
.quad LFB4a-.
.set L$set$48a,LFE4a-LFB4a
.quad L$set$48a
.byte 0x0
.byte 0x4
.set L$set$49a,LCFI38a-LFB4a
.long L$set$49a
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$50a,LCFI39a-LCFI38a
.long L$set$50a
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$51a,LCFI44a-LCFI39a
.long L$set$51a
.byte 0x8e
.byte 0x6
.byte 0x8d
.byte 0x5
.byte 0x8c
.byte 0x4
.byte 0x83
.byte 0x3
.align 3
LEFDE21a:
.globl _test_rbx_r12_r13_r14_r15.eh
_test_rbx_r12_r13_r14_r15.eh:
LSFDE23:
.set L$set$52,LEFDE23-LASFDE23
.long L$set$52
LASFDE23:
.long LASFDE23-EH_frame1
.quad LFB3-.
.set L$set$53,LFE3-LFB3
.quad L$set$53
.byte 0x0
.byte 0x4
.set L$set$54,LCFI45-LFB3
.long L$set$54
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$55,LCFI46-LCFI45
.long L$set$55
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$56,LCFI52-LCFI46
.long L$set$56
.byte 0x8f
.byte 0x3
.byte 0x8e
.byte 0x4
.byte 0x8d
.byte 0x5
.byte 0x8c
.byte 0x6
.byte 0x83
.byte 0x7
.align 3
LEFDE23:
.globl _test_r13_rbx_r14_r15_r12.eh
_test_r13_rbx_r14_r15_r12.eh:
LSFDE23a:
.set L$set$52a,LEFDE23a-LASFDE23a
.long L$set$52a
LASFDE23a:
.long LASFDE23a-EH_frame1
.quad LFB3a-.
.set L$set$53a,LFE3a-LFB3a
.quad L$set$53a
.byte 0x0
.byte 0x4
.set L$set$54a,LCFI45a-LFB3a
.long L$set$54a
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$55a,LCFI46a-LCFI45a
.long L$set$55a
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$56a,LCFI52a-LCFI46a
.long L$set$56a
.byte 0x8c
.byte 0x3
.byte 0x8f
.byte 0x4
.byte 0x8e
.byte 0x5
.byte 0x83
.byte 0x6
.byte 0x8d
.byte 0x7
.align 3
LEFDE23a:
#endif // USE_EH_FRAME
#if USE_COMPACT_UNWIND
.section __LD,__compact_unwind,regular,debug
.quad _test_no_reg
.set L101,LFE13-_test_no_reg
.long L101
.long 0x01000000
.quad 0
.quad 0
.quad _test_rbx
.set L102,LFE10-_test_rbx
.long L102
.long 0x01010001
.quad 0
.quad 0
.quad _test_rbx_r12
.set L103,LFE8-_test_rbx_r12
.long L103
.long 0x01020011
.quad 0
.quad 0
.quad _test_rbx_r14
.set L104,LFE8a-_test_rbx_r14
.long L104
.long 0x01020021
.quad 0
.quad 0
.quad _test_rbx_r12_r13
.set L105,LFE6-_test_rbx_r12_r13
.long L105
.long 0x010300D1
.quad 0
.quad 0
.quad _test_rbx_r12_r13_r14
.set L106,LFE4-_test_rbx_r12_r13_r14
.long L106
.long 0x010408D1
.quad 0
.quad 0
.quad _test_r14_r13_r12_rbx
.set L107,LFE4a-_test_r14_r13_r12_rbx
.long L107
.long 0x0104029C
.quad 0
.quad 0
.quad _test_rbx_r12_r13_r14_r15
.set L108,LFE3-_test_rbx_r12_r13_r14_r15
.long L108
.long 0x010558D1
.quad 0
.quad 0
.quad _test_r13_rbx_r14_r15_r12
.set L109,LFE3a-_test_r13_rbx_r14_r15_r12
.long L109
.long 0x01052B0B
.quad 0
.quad 0
#endif // USE_COMPACT_UNWIND
.subsections_via_symbols

View File

@ -0,0 +1,583 @@
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -Wl,-no_compact_unwind
.data
.globl _unwind_tester_list
_unwind_tester_list:
.quad _test_no_reg
.quad _test_rbx
.quad _test_rbx_r12
.quad _test_rbx_r12_r13
.quad _test_rbx_r12_r13_r14
.quad _test_rbx_r12_r13_r14_r15
.quad _test_rbx_rbp
.quad _test_rbx_rbp_r12
.quad _test_rbx_rbp_r12_r13
.quad _test_rbx_rbp_r12_r13_r14
.quad _test_rbx_rbp_r12_r13_r14_r15
.quad 0
.text
.globl _test_no_reg
_test_no_reg:
LFB13:
subq $8, %rsp
LCFI0:
call _uwind_to_main
addq $8, %rsp
ret
LFE13:
.globl _test_rbx
_test_rbx:
LFB10:
pushq %rbx
LCFI3:
movq $0, %rbx
call _uwind_to_main
popq %rbx
ret
LFE10:
.globl _test_rbx_r12
_test_rbx_r12:
LFB8:
movq %rbx, -16(%rsp)
LCFI5:
movq %r12, -8(%rsp)
LCFI6:
subq $24, %rsp
LCFI7:
movq $0, %rbx
movq $0, %r12
call _uwind_to_main
movq 8(%rsp), %rbx
movq 16(%rsp), %r12
addq $24, %rsp
ret
LFE8:
.globl _test_rbx_rbp
_test_rbx_rbp:
LFB7:
movq %rbx, -16(%rsp)
LCFI8:
movq %rbp, -8(%rsp)
LCFI9:
subq $24, %rsp
LCFI10:
movq $0, %rbp
movq $0, %rbx
call _uwind_to_main
movq 8(%rsp), %rbx
movq 16(%rsp), %rbp
addq $24, %rsp
ret
LFE7:
.globl _test_rbx_r12_r13
_test_rbx_r12_r13:
LFB6:
movq %rbx, -24(%rsp)
LCFI11:
movq %r12, -16(%rsp)
LCFI12:
movq %r13, -8(%rsp)
LCFI13:
subq $24, %rsp
LCFI14:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
call _uwind_to_main
movq (%rsp), %rbx
movq 8(%rsp), %r12
movq 16(%rsp), %r13
addq $24, %rsp
ret
LFE6:
.globl _test_rbx_r12_r13_r14
_test_rbx_r12_r13_r14:
LFB4:
movq %rbx, -32(%rsp)
LCFI19:
movq %r12, -24(%rsp)
LCFI20:
movq %r13, -16(%rsp)
LCFI21:
movq %r14, -8(%rsp)
LCFI22:
subq $40, %rsp
LCFI23:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
movq $0, %r14
call _uwind_to_main
movq 8(%rsp), %rbx
movq 16(%rsp), %r12
movq 24(%rsp), %r13
movq 32(%rsp), %r14
addq $40, %rsp
ret
LFE4:
.globl _test_rbx_r12_r13_r14_r15
_test_rbx_r12_r13_r14_r15:
LFB3:
movq %rbx, -40(%rsp)
LCFI24:
movq %r12, -32(%rsp)
LCFI25:
movq %r13, -24(%rsp)
LCFI26:
movq %r14, -16(%rsp)
LCFI27:
movq %r15, -8(%rsp)
LCFI28:
subq $40, %rsp
LCFI29:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
movq $0, %r14
movq $0, %r15
call _uwind_to_main
movq (%rsp), %rbx
movq 8(%rsp), %r12
movq 16(%rsp), %r13
movq 24(%rsp), %r14
movq 32(%rsp), %r15
addq $40, %rsp
ret
LFE3:
.globl _test_rbx_rbp_r12_r13_r14_r15
_test_rbx_rbp_r12_r13_r14_r15:
LFB2:
movq %rbx, -48(%rsp)
LCFI30:
movq %rbp, -40(%rsp)
LCFI31:
movq %r12, -32(%rsp)
LCFI32:
movq %r13, -24(%rsp)
LCFI33:
movq %r14, -16(%rsp)
LCFI34:
movq %r15, -8(%rsp)
LCFI35:
subq $72, %rsp
LCFI36:
movq $0, %rbx
movq $0, %rbp
movq $0, %r12
movq $0, %r13
movq $0, %r14
movq $0, %r15
call _uwind_to_main
movq 24(%rsp), %rbx
movq 32(%rsp), %rbp
movq 40(%rsp), %r12
movq 48(%rsp), %r13
movq 56(%rsp), %r14
movq 64(%rsp), %r15
addq $72, %rsp
ret
LFE2:
.globl _test_rbx_rbp_r12
_test_rbx_rbp_r12:
LFB11:
movq %rbx, -24(%rsp)
movq %rbp, -16(%rsp)
movq %r12, -8(%rsp)
subq $24, %rsp
LCFI11a:
movq $0, %rbx
movq $0, %rbp
movq $0, %r12
call _uwind_to_main
movq (%rsp), %rbx
movq 8(%rsp), %rbp
movq 16(%rsp), %r12
addq $24, %rsp
ret
LFE11:
.globl _test_rbx_rbp_r12_r13
_test_rbx_rbp_r12_r13:
LFB457:
movq %rbx, -32(%rsp)
movq %rbp, -24(%rsp)
movq %r12, -16(%rsp)
movq %r13, -8(%rsp)
subq $40, %rsp
LFB457a:
movq $0, %rbx
movq $0, %rbp
movq $0, %r12
movq $0, %r13
call _uwind_to_main
movq 8(%rsp), %rbx
movq 16(%rsp), %rbp
movq 24(%rsp), %r12
movq 32(%rsp), %r13
addq $40, %rsp
ret
LFE457:
.globl _test_rbx_rbp_r12_r13_r14
_test_rbx_rbp_r12_r13_r14:
LFB17:
movq %rbx, -40(%rsp)
movq %rbp, -32(%rsp)
movq %r12, -24(%rsp)
movq %r13, -16(%rsp)
movq %r14, -8(%rsp)
subq $40, %rsp
LFB17a:
movq $0, %rbx
movq $0, %rbp
movq $0, %r12
movq $0, %r13
movq $0, %r14
call _uwind_to_main
movq (%rsp), %rbx
movq 8(%rsp), %rbp
movq 16(%rsp), %r12
movq 24(%rsp), %r13
movq 32(%rsp), %r14
addq $40, %rsp
ret
LFE17:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 # Length of Common Information Entry
LSCIE1:
.long 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
.byte 0x78 # sleb128 -8; CIE Data Alignment Factor
.byte 0x10 # CIE RA Column
.byte 0x1 # uleb128 0x1; Augmentation size
.byte 0x10 # FDE Encoding (pcrel)
.byte 0xc # DW_CFA_def_cfa
.byte 0x7 # uleb128 0x7
.byte 0x8 # uleb128 0x8
.byte 0x90 # DW_CFA_offset, column 0x10
.byte 0x1 # uleb128 0x1
.align 3
LECIE1:
.globl _test_no_reg.eh
_test_no_reg.eh:
LSFDE3:
.set L$set$3,LEFDE3-LASFDE3
.long L$set$3 # FDE Length
LASFDE3:
.long LASFDE3-EH_frame1 # FDE CIE offset
.quad LFB13-. # FDE initial location
.set L$set$4,LFE13-LFB13
.quad L$set$4 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$5,LCFI0-LFB13
.long L$set$5
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x10 # uleb128 0x10
.align 3
LEFDE3:
.globl _test_rbx.eh
_test_rbx.eh:
LSFDE9:
.set L$set$12,LEFDE9-LASFDE9
.long L$set$12 # FDE Length
LASFDE9:
.long LASFDE9-EH_frame1 # FDE CIE offset
.quad LFB10-. # FDE initial location
.set L$set$13,LFE10-LFB10
.quad L$set$13 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$14,LCFI3-LFB10
.long L$set$14
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x10 # uleb128 0x10
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x2 # uleb128 0x2
.align 3
LEFDE9:
.globl _test_rbx_r12.eh
_test_rbx_r12.eh:
LSFDE13:
.set L$set$18,LEFDE13-LASFDE13
.long L$set$18 # FDE Length
LASFDE13:
.long LASFDE13-EH_frame1 # FDE CIE offset
.quad LFB8-. # FDE initial location
.set L$set$19,LFE8-LFB8
.quad L$set$19 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$20,LCFI7-LFB8
.long L$set$20
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x2 # uleb128 0x2
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.align 3
LEFDE13:
.globl _test_rbx_rbp.eh
_test_rbx_rbp.eh:
LSFDE14:
.set L$set$21,LEFDE14-LASFDE14
.long L$set$21 # FDE Length
LASFDE14:
.long LASFDE14-EH_frame1 # FDE CIE offset
.quad LFB7-. # FDE initial location
.set L$set$22,LFE7-LFB7
.quad L$set$22 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$23,LCFI10-LFB7
.long L$set$23
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x2 # uleb128 0x2
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.align 3
LEFDE14:
.globl _test_rbx_r12_r13.eh
_test_rbx_r12_r13.eh:
LSFDE17:
.set L$set$24,LEFDE17-LASFDE17
.long L$set$24 # FDE Length
LASFDE17:
.long LASFDE17-EH_frame1 # FDE CIE offset
.quad LFB6-. # FDE initial location
.set L$set$25,LFE6-LFB6
.quad L$set$25 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$26,LCFI14-LFB6
.long L$set$26
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x2 # uleb128 0x2
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x3 # uleb128 0x3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 3
LEFDE17:
.globl _test_rbx_r12_r13_r14.eh
_test_rbx_r12_r13_r14.eh:
LSFDE21:
.set L$set$30,LEFDE21-LASFDE21
.long L$set$30 # FDE Length
LASFDE21:
.long LASFDE21-EH_frame1 # FDE CIE offset
.quad LFB4-. # FDE initial location
.set L$set$31,LFE4-LFB4
.quad L$set$31 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$32,LCFI23-LFB4
.long L$set$32
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x30 # uleb128 0x30
.byte 0x8e # DW_CFA_offset, column 0xe
.byte 0x2 # uleb128 0x2
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x3 # uleb128 0x3
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x4 # uleb128 0x4
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x5 # uleb128 0x5
.align 3
LEFDE21:
.globl _test_rbx_r12_r13_r14_r15.eh
_test_rbx_r12_r13_r14_r15.eh:
LSFDE23:
.set L$set$33,LEFDE23-LASFDE23
.long L$set$33 # FDE Length
LASFDE23:
.long LASFDE23-EH_frame1 # FDE CIE offset
.quad LFB3-. # FDE initial location
.set L$set$34,LFE3-LFB3
.quad L$set$34 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$35,LCFI29-LFB3
.long L$set$35
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x30 # uleb128 0x30
.byte 0x8f # DW_CFA_offset, column 0xf
.byte 0x2 # uleb128 0x2
.byte 0x8e # DW_CFA_offset, column 0xe
.byte 0x3 # uleb128 0x3
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x4 # uleb128 0x4
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x5 # uleb128 0x5
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x6 # uleb128 0x6
.align 3
LEFDE23:
.globl _test_rbx_rbp_r12_r13_r14_r15.eh
_test_rbx_rbp_r12_r13_r14_r15.eh:
LSFDE25:
.set L$set$36,LEFDE25-LASFDE25
.long L$set$36 # FDE Length
LASFDE25:
.long LASFDE25-EH_frame1 # FDE CIE offset
.quad LFB2-. # FDE initial location
.set L$set$37,LFE2-LFB2
.quad L$set$37 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$38,LCFI36-LFB2
.long L$set$38
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x50 # uleb128 0x50
.byte 0x8f # DW_CFA_offset, column 0xf
.byte 0x2 # uleb128 0x2
.byte 0x8e # DW_CFA_offset, column 0xe
.byte 0x3 # uleb128 0x3
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x4 # uleb128 0x4
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x5 # uleb128 0x5
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x6 # uleb128 0x6
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x7 # uleb128 0x7
.align 3
LEFDE25:
.globl _test_rbx_rbp_r12.eh
_test_rbx_rbp_r12.eh:
LSFDE11:
.set L$set$24a,LEFDE11-LASFDE11
.long L$set$24a # FDE Length
LASFDE11:
.long LASFDE11-EH_frame1 # FDE CIE offset
.quad LFB11-. # FDE initial location
.set L$set$25a,LFE11-LFB11
.quad L$set$25a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$26a,LCFI11a-LFB11
.long L$set$26a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x2 # uleb128 0x2
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x3 # uleb128 0x3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 3
LEFDE11:
.globl _test_rbx_rbp_r12_r13.eh
_test_rbx_rbp_r12_r13.eh:
.set L$set$30a,LEFDE457-LASFDE457
.long L$set$30a # FDE Length
LASFDE457:
.long LASFDE457-EH_frame1 # FDE CIE offset
.quad LFB457-. # FDE initial location
.set L$set$31a,LFE457-LFB457
.quad L$set$31a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$32a,LCFI23-LFB4
.long L$set$32a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x30 # uleb128 0x30
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x2 # uleb128 0x2
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x5 # uleb128 0x5
.align 3
LEFDE457:
.globl _test_rbx_rbp_r12_r13_r14.eh
_test_rbx_rbp_r12_r13_r14.eh:
.set L$set$33a,LEFDE117-LASFDE117
.long L$set$33a # FDE Length
LASFDE117:
.long LASFDE117-EH_frame1 # FDE CIE offset
.quad LFB17-. # FDE initial location
.set L$set$34a,LFE17-LFB17
.quad L$set$34a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$35a,LCFI29-LFB3
.long L$set$35a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x30 # uleb128 0x30
.byte 0x8e # DW_CFA_offset, column 0xe
.byte 0x2 # uleb128 0x2
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x3 # uleb128 0x3
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x4 # uleb128 0x4
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x5 # uleb128 0x5
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x6 # uleb128 0x6
.align 3
LEFDE117:
.subsections_via_symbols

View File

@ -0,0 +1,598 @@
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -Wl,-no_compact_unwind
.data
.globl _unwind_tester_list
_unwind_tester_list:
.quad _test_no_reg
.quad _test_rbx
.quad _test_rbx_r12
.quad _test_rbx_r12_r13
.quad _test_rbx_r12_r13_r14
.quad _test_rbx_r12_r13_r14_r15
.quad _test_rbx_rbp
.quad _test_rbx_rbp_r12
.quad _test_rbx_rbp_r12_r13
.quad _test_rbx_rbp_r12_r13_r14
.quad _test_rbx_rbp_r12_r13_r14_r15
.quad 0
.text
.globl _test_no_reg
_test_no_reg:
LFB13:
subq $160008, %rsp
LCFI0:
call _uwind_to_main
addq $160008, %rsp
ret
LFE13:
.globl _test_rbx
_test_rbx:
LFB10:
pushq %rbx
LCFI3:
subq $160000, %rsp
LCFI4:
movq $0, %rbx
call _uwind_to_main
addq $160000, %rsp
popq %rbx
ret
LFE10:
.globl _test_rbx_r12
_test_rbx_r12:
LFB8:
movq %rbx, -16(%rsp)
LCFI7:
movq %r12, -8(%rsp)
LCFI8:
subq $160024, %rsp
LCFI9:
movq $0, %rbx
movq $0, %r12
call _uwind_to_main
movq 160008(%rsp), %rbx
movq 160016(%rsp), %r12
addq $160024, %rsp
ret
LFE8:
.globl _test_rbx_rbp
_test_rbx_rbp:
LFB7:
movq %rbx, -16(%rsp)
LCFI10:
movq %rbp, -8(%rsp)
LCFI11:
subq $160024, %rsp
LCFI12:
movq $0, %rbp
movq $0, %rbx
call _uwind_to_main
movq 160008(%rsp), %rbx
movq 160016(%rsp), %rbp
addq $160024, %rsp
ret
LFE7:
.globl _test_rbx_r12_r13
_test_rbx_r12_r13:
LFB6:
movq %rbx, -24(%rsp)
LCFI13:
movq %r12, -16(%rsp)
LCFI14:
movq %r13, -8(%rsp)
LCFI15:
subq $160024, %rsp
LCFI16:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
call _uwind_to_main
movq 160000(%rsp), %rbx
movq 160008(%rsp), %r12
movq 160016(%rsp), %r13
addq $160024, %rsp
ret
LFE6:
.globl _test_rbx_rbp_r12
_test_rbx_rbp_r12:
LFB9:
movq %rbx, -24(%rsp)
movq %rbp, -16(%rsp)
movq %r12, -8(%rsp)
subq $160024, %rsp
LCFI9a:
movq $0, %rbx
movq $0, %rbp
movq $0, %r12
call _uwind_to_main
movq 160000(%rsp), %rbx
movq 160008(%rsp), %rbp
movq 160016(%rsp), %r12
addq $160024, %rsp
ret
LFE9:
.globl _test_rbx_r12_r13_r14
_test_rbx_r12_r13_r14:
LFB4:
movq %rbx, -32(%rsp)
LCFI21:
movq %r12, -24(%rsp)
LCFI22:
movq %r13, -16(%rsp)
LCFI23:
movq %r14, -8(%rsp)
LCFI24:
subq $160040, %rsp
LCFI25:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
movq $0, %r14
call _uwind_to_main
movq 160008(%rsp), %rbx
movq 160016(%rsp), %r12
movq 160024(%rsp), %r13
movq 160032(%rsp), %r14
addq $160040, %rsp
ret
LFE4:
.globl _test_rbx_r12_r13_r14_r15
_test_rbx_r12_r13_r14_r15:
LFB3:
movq %rbx, -40(%rsp)
LCFI26:
movq %r12, -32(%rsp)
LCFI27:
movq %r13, -24(%rsp)
LCFI28:
movq %r14, -16(%rsp)
LCFI29:
movq %r15, -8(%rsp)
LCFI30:
subq $160040, %rsp
LCFI31:
movq $0, %rbx
movq $0, %r12
movq $0, %r13
movq $0, %r14
movq $0, %r15
call _uwind_to_main
movq 160000(%rsp), %rbx
movq 160008(%rsp), %r12
movq 160016(%rsp), %r13
movq 160024(%rsp), %r14
movq 160032(%rsp), %r15
addq $160040, %rsp
ret
LFE3:
.globl _test_rbx_rbp_r12_r13_r14_r15
_test_rbx_rbp_r12_r13_r14_r15:
LFB2:
movq %rbx, -48(%rsp)
LCFI32:
movq %rbp, -40(%rsp)
LCFI33:
movq %r12, -32(%rsp)
LCFI34:
movq %r13, -24(%rsp)
LCFI35:
movq %r14, -16(%rsp)
LCFI36:
movq %r15, -8(%rsp)
LCFI37:
subq $160072, %rsp
LCFI38:
movq $0, %rbx
movq $0, %rbp
movq $0, %r12
movq $0, %r13
movq $0, %r14
movq $0, %r15
call _uwind_to_main
movq 160024(%rsp), %rbx
movq 160032(%rsp), %rbp
movq 160040(%rsp), %r12
movq 160048(%rsp), %r13
movq 160056(%rsp), %r14
movq 160064(%rsp), %r15
addq $160072, %rsp
ret
LFE2:
.globl _test_rbx_rbp_r12_r13
_test_rbx_rbp_r12_r13:
LFB457:
movq %rbx, -32(%rsp)
LCFI18:
movq %rbp, -24(%rsp)
LCFI19:
movq %r12, -16(%rsp)
movq %r13, -8(%rsp)
subq $160040, %rsp
LCFI20:
movq $0, %rbx
movq $0, %rbp
movq $0, %r12
movq $0, %r13
call _uwind_to_main
movq 160008(%rsp), %rbx
movq 160016(%rsp), %rbp
movq 160024(%rsp), %r12
movq 160032(%rsp), %r13
addq $160040, %rsp
ret
LFE457:
.globl _test_rbx_rbp_r12_r13_r14
_test_rbx_rbp_r12_r13_r14:
LFB17:
movq %rbx, -40(%rsp)
movq %rbp, -32(%rsp)
movq %r12, -24(%rsp)
movq %r13, -16(%rsp)
movq %r14, -8(%rsp)
subq $160040, %rsp
LFB17a:
movq $0, %rbx
movq $0, %rbp
movq $0, %r12
movq $0, %r13
movq $0, %r14
call _uwind_to_main
movq 160000(%rsp), %rbx
movq 160008(%rsp), %rbp
movq 160016(%rsp), %r12
movq 160024(%rsp), %r13
movq 160032(%rsp), %r14
addq $160040, %rsp
ret
LFE17:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 # Length of Common Information Entry
LSCIE1:
.long 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
.byte 0x78 # sleb128 -8; CIE Data Alignment Factor
.byte 0x10 # CIE RA Column
.byte 0x1 # uleb128 0x1; Augmentation size
.byte 0x10 # FDE Encoding (pcrel)
.byte 0xc # DW_CFA_def_cfa
.byte 0x7 # uleb128 0x7
.byte 0x8 # uleb128 0x8
.byte 0x90 # DW_CFA_offset, column 0x10
.byte 0x1 # uleb128 0x1
.align 3
LECIE1:
.globl _test_no_reg.eh
_test_no_reg.eh:
LSFDE3:
.set L$set$3,LEFDE3-LASFDE3
.long L$set$3 # FDE Length
LASFDE3:
.long LASFDE3-EH_frame1 # FDE CIE offset
.quad LFB13-. # FDE initial location
.set L$set$4,LFE13-LFB13
.quad L$set$4 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$5,LCFI0-LFB13
.long L$set$5
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x90,0xe2,0x9 # uleb128 0x27110
.align 3
LEFDE3:
.globl _test_rbx.eh
_test_rbx.eh:
LSFDE9:
.set L$set$12,LEFDE9-LASFDE9
.long L$set$12 # FDE Length
LASFDE9:
.long LASFDE9-EH_frame1 # FDE CIE offset
.quad LFB10-. # FDE initial location
.set L$set$13,LFE10-LFB10
.quad L$set$13 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$14,LCFI3-LFB10
.long L$set$14
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x10 # uleb128 0x10
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$15,LCFI4-LCFI3
.long L$set$15
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x90,0xe2,0x9 # uleb128 0x27110
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x2 # uleb128 0x2
.align 3
LEFDE9:
.globl _test_rbx_r12.eh
_test_rbx_r12.eh:
LSFDE13:
.set L$set$20,LEFDE13-LASFDE13
.long L$set$20 # FDE Length
LASFDE13:
.long LASFDE13-EH_frame1 # FDE CIE offset
.quad LFB8-. # FDE initial location
.set L$set$21,LFE8-LFB8
.quad L$set$21 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$22,LCFI9-LFB8
.long L$set$22
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xe2,0x9 # uleb128 0x27120
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x2 # uleb128 0x2
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.align 3
LEFDE13:
.globl _test_rbx_rbp.eh
_test_rbx_rbp.eh:
LSFDE14:
.set L$set$23,LEFDE14-LASFDE14
.long L$set$23 # FDE Length
LASFDE14:
.long LASFDE14-EH_frame1 # FDE CIE offset
.quad LFB7-. # FDE initial location
.set L$set$24,LFE7-LFB7
.quad L$set$24 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$25,LCFI12-LFB7
.long L$set$25
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xe2,0x9 # uleb128 0x27120
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x2 # uleb128 0x2
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.align 3
LEFDE14:
.globl _test_rbx_r12_r13.eh
_test_rbx_r12_r13.eh:
LSFDE17:
.set L$set$26,LEFDE17-LASFDE17
.long L$set$26 # FDE Length
LASFDE17:
.long LASFDE17-EH_frame1 # FDE CIE offset
.quad LFB6-. # FDE initial location
.set L$set$27,LFE6-LFB6
.quad L$set$27 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$28,LCFI16-LFB6
.long L$set$28
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xe2,0x9 # uleb128 0x27120
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x2 # uleb128 0x2
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x3 # uleb128 0x3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 3
LEFDE17:
.globl _test_rbx_r12_r13_r14.eh
_test_rbx_r12_r13_r14.eh:
LSFDE21:
.set L$set$32,LEFDE21-LASFDE21
.long L$set$32 # FDE Length
LASFDE21:
.long LASFDE21-EH_frame1 # FDE CIE offset
.quad LFB4-. # FDE initial location
.set L$set$33,LFE4-LFB4
.quad L$set$33 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$34,LCFI25-LFB4
.long L$set$34
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xb0,0xe2,0x9 # uleb128 0x27130
.byte 0x8e # DW_CFA_offset, column 0xe
.byte 0x2 # uleb128 0x2
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x3 # uleb128 0x3
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x4 # uleb128 0x4
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x5 # uleb128 0x5
.align 3
LEFDE21:
.globl _test_rbx_r12_r13_r14_r15.eh
_test_rbx_r12_r13_r14_r15.eh:
LSFDE23:
.set L$set$35,LEFDE23-LASFDE23
.long L$set$35 # FDE Length
LASFDE23:
.long LASFDE23-EH_frame1 # FDE CIE offset
.quad LFB3-. # FDE initial location
.set L$set$36,LFE3-LFB3
.quad L$set$36 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$37,LCFI31-LFB3
.long L$set$37
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xb0,0xe2,0x9 # uleb128 0x27130
.byte 0x8f # DW_CFA_offset, column 0xf
.byte 0x2 # uleb128 0x2
.byte 0x8e # DW_CFA_offset, column 0xe
.byte 0x3 # uleb128 0x3
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x4 # uleb128 0x4
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x5 # uleb128 0x5
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x6 # uleb128 0x6
.align 3
LEFDE23:
.globl _test_rbx_rbp_r12_r13_r14_r15.eh
_test_rbx_rbp_r12_r13_r14_r15.eh:
LSFDE25:
.set L$set$38,LEFDE25-LASFDE25
.long L$set$38 # FDE Length
LASFDE25:
.long LASFDE25-EH_frame1 # FDE CIE offset
.quad LFB2-. # FDE initial location
.set L$set$39,LFE2-LFB2
.quad L$set$39 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$40,LCFI38-LFB2
.long L$set$40
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xd0,0xe2,0x9 # uleb128 0x27150
.byte 0x8f # DW_CFA_offset, column 0xf
.byte 0x2 # uleb128 0x2
.byte 0x8e # DW_CFA_offset, column 0xe
.byte 0x3 # uleb128 0x3
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x4 # uleb128 0x4
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x5 # uleb128 0x5
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x6 # uleb128 0x6
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x7 # uleb128 0x7
.align 3
LEFDE25:
.globl _test_rbx_rbp_r12_r13.eh
_test_rbx_rbp_r12_r13.eh:
LSFDE11:
.set L$set$17a,LEFDE11-LASFDE11
.long L$set$17a # FDE Length
LASFDE11:
.long LASFDE11-EH_frame1 # FDE CIE offset
.quad LFB457-. # FDE initial location
.set L$set$18a,LFE457-LFB457
.quad L$set$18a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$19a,LCFI20-LFB457
.long L$set$19a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xb0,0xe2,0x9 # uleb128 0x27130
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x2 # uleb128 0x2
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x5 # uleb128 0x5
.align 3
LEFDE11:
.globl _test_rbx_rbp_r12_r13_r14.eh
_test_rbx_rbp_r12_r13_r14.eh:
LSFDE7:
.set L$set$35a,LEFDE7-LASFDE7
.long L$set$35a # FDE Length
LASFDE7:
.long LASFDE7-EH_frame1 # FDE CIE offset
.quad LFB17-. # FDE initial location
.set L$set$36a,LFE17-LFB17
.quad L$set$36a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$37a,LFB17a-LFB17
.long L$set$37a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xb0,0xe2,0x9 # uleb128 0x27130
.byte 0x8e # DW_CFA_offset, column 0xe
.byte 0x2 # uleb128 0x2
.byte 0x8d # DW_CFA_offset, column 0xd
.byte 0x3 # uleb128 0x3
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x4 # uleb128 0x4
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x5 # uleb128 0x5
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x6 # uleb128 0x6
.align 3
LEFDE7:
.globl _test_rbx_rbp_r12.eh
_test_rbx_rbp_r12.eh:
LSFDE19:
.set L$set$26a,LEFDE19-LASFDE19
.long L$set$26a # FDE Length
LASFDE19:
.long LASFDE19-EH_frame1 # FDE CIE offset
.quad LFB9-. # FDE initial location
.set L$set$27a,LFE9-LFB9
.quad L$set$27a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$28a,LCFI9a-LFB9
.long L$set$28a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xe2,0x9 # uleb128 0x27120
.byte 0x8c # DW_CFA_offset, column 0xc
.byte 0x2 # uleb128 0x2
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x3 # uleb128 0x3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 3
LEFDE19:
.subsections_via_symbols

View File

@ -0,0 +1,311 @@
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86_64.s -arch x86_64 -Wl,-no_compact_unwind
.data
.globl _unwind_tester_list
_unwind_tester_list:
.quad _test_no_reg
.quad Ltest_rbx
.quad _test_rbx_pad_r12
.quad _test_rbx_same_value
.quad _test_rbx_same_register
.quad 0
.text
.globl _test_big_frameless_stack_odd_dwarf
_test_big_frameless_stack_odd_dwarf:
L100:
subq $160016, %rsp
L102:
movq $0, %rbx
call _uwind_to_main
addq $160016, %rsp
ret
L103:
LFE14:
.globl _test_no_reg
_test_no_reg:
LFB13:
pushq %rbp
LCFI2:
movq %rsp, %rbp
LCFI3:
call _uwind_to_main
leave
ret
LFE13:
Ltest_rbx:
LFB10:
pushq %rbp
LCFI8:
movq %rsp, %rbp
LCFI9:
pushq %rbx
LCFI10:
subq $8, %rsp
LCFI11:
movq $0, %rbx
call _uwind_to_main
addq $8, %rsp
popq %rbx
leave
ret
LFE10:
.globl _test_rbx_pad_r12
_test_rbx_pad_r12:
LFB8:
pushq %rbp
LCFI16:
movq %rsp, %rbp
LCFI17:
movq %rbx, -56(%rbp)
LCFI18:
movq %r12, -8(%rbp)
LCFI19:
subq $64, %rsp
LCFI20:
movq $0, %rbx
movq $0, %r12
call _uwind_to_main
movq (%rsp), %rbx
movq 8(%rsp), %r12
leave
ret
LFE8:
.globl _test_rbx_same_value
_test_rbx_same_value:
LFB10b:
jmp L33
pushq %rbx
LCFI3b:
movq $0, %rbx
call _uwind_to_main
popq %rbx
ret
L33:
pushq $0
call _uwind_to_main
popq %rax
ret
LFE10b:
.globl _test_rbx_same_register
_test_rbx_same_register:
LFB10c:
jmp L34
pushq %rbx
LCFI3c:
movq $0, %rbx
call _uwind_to_main
popq %rbx
ret
L34:
pushq $0
call _uwind_to_main
popq %rax
ret
LFE10c:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0
LSCIE1:
.long 0x0
.byte 0x1
.ascii "zR\0"
.byte 0x1
.byte 0x78
.byte 0x10
.byte 0x1
.byte 0x10
.byte 0xc
.byte 0x7
.byte 0x8
.byte 0x90
.byte 0x1
.align 3
LECIE1:
.globl _test_no_reg.eh
_test_no_reg.eh:
LSFDE3:
.set L$set$5,LEFDE3-LASFDE3
.long L$set$5
LASFDE3:
.long LASFDE3-EH_frame1
.quad LFB13-.
.set L$set$6,LFE13-LFB13
.quad L$set$6
.byte 0x0
.byte 0x4
.set L$set$7,LCFI2-LFB13
.long L$set$7
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$8,LCFI3-LCFI2
.long L$set$8
.byte 0xd
.byte 0x6
.align 3
LEFDE3:
Ltest_rbx.eh:
LSFDE9:
.set L$set$17,LEFDE9-LASFDE9
.long L$set$17
LASFDE9:
.long LASFDE9-EH_frame1
.quad LFB10-.
.set L$set$18,LFE10-LFB10
.quad L$set$18
.byte 0x0
.byte 0x4
.set L$set$19,LCFI8-LFB10
.long L$set$19
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$20,LCFI9-LCFI8
.long L$set$20
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$21,LCFI11-LCFI9
.long L$set$21
.byte 0x83
.byte 0x3
.align 3
LEFDE9:
.globl _test_rbx_pad_r12.eh
_test_rbx_pad_r12.eh:
LSFDE13:
.set L$set$27,LEFDE13-LASFDE13
.long L$set$27
LASFDE13:
.long LASFDE13-EH_frame1
.quad LFB8-.
.set L$set$28,LFE8-LFB8
.quad L$set$28
.byte 0x0
.byte 0x4
.set L$set$29,LCFI16-LFB8
.long L$set$29
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$30,LCFI17-LCFI16
.long L$set$30
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$31,LCFI20-LCFI17
.long L$set$31
.byte 0x8c
.byte 0x3
.byte 0x83
.byte 0x9
.align 3
LEFDE13:
.globl _test_big_frameless_stack_odd_dwarf.eh
_test_big_frameless_stack_odd_dwarf.eh:
.set L$set$12a,LEFDE9a-LASFDE9a
.long L$set$12a # FDE Length
LASFDE9a:
.long LASFDE9a-EH_frame1 # FDE CIE offset
.quad L100-. # FDE initial location
.set L$set$13a,L103-L100
.quad L$set$13a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.long 7
.byte 0xc # DW_CFA_def_cfa
.byte 0x07 # uleb128 7
.byte 0x90,0xe2,0x9 # uleb128 0x27110
.align 3
LEFDE9a:
.globl _test_rbx_same_value.eh
_test_rbx_same_value.eh:
LSFDE9b:
.set L$set$12,LEFDE9b-LASFDE9b
.long L$set$12 # FDE Length
LASFDE9b:
.long LASFDE9b-EH_frame1 # FDE CIE offset
.quad LFB10b-. # FDE initial location
.set L$set$13,LFE10b-LFB10b
.quad L$set$13 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$14,LCFI3b-LFB10b
.long L$set$14
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x10 # uleb128 0x10
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$15,L33-LCFI3b
.long L$set$15
.byte 0x08 # DW_CFA_same_value
.byte 0x3 # uleb128 0x3
.align 3
LEFDE9b:
.globl _test_rbx_same_register.eh
_test_rbx_same_register.eh:
LSFDE9c:
.set L$set$12c,LEFDE9c-LASFDE9c
.long L$set$12c # FDE Length
LASFDE9c:
.long LASFDE9c-EH_frame1 # FDE CIE offset
.quad LFB10c-. # FDE initial location
.set L$set$16c,LFE10c-LFB10c
.quad L$set$16c # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$17c,LCFI3c-LFB10c
.long L$set$17c
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x10 # uleb128 0x10
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$18c,L34-LCFI3c
.long L$set$18c
.byte 0x09 # DW_CFA_register
.byte 0x3 # uleb128 0x3
.byte 0x3 # uleb128 0x3
.align 3
LEFDE9c:

View File

@ -0,0 +1,589 @@
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions
.data
.globl _unwind_tester_list
_unwind_tester_list:
.long _test_no_reg
.long _test_ebx
.long _test_esi
.long _test_edi
.long _test_ebx_esi
.long _test_esi_edi
.long _test_ebx_edi
.long _test_ebx_esi_edi
.long _test_edi_esi_ebx
.long _test_pad_ebx_edi
.long 0
.text
.globl _test_ebx
_test_ebx:
LFB13:
pushl %ebp
LCFI2:
movl %esp, %ebp
LCFI3:
pushl %ebx
LCFI4:
subl $20, %esp
LCFI5:
movl $0, %ebx
call _uwind_to_main
addl $20, %esp
popl %ebx
leave
ret
LFE13:
.globl _test_no_reg
_test_no_reg:
LFB12:
pushl %ebp
LCFI6:
movl %esp, %ebp
LCFI7:
subl $24, %esp
LCFI8:
call _uwind_to_main
leave
ret
LFE12:
.globl _test_esi
_test_esi:
LFB10:
pushl %ebp
LCFI13:
movl %esp, %ebp
LCFI14:
pushl %esi
LCFI15:
subl $20, %esp
LCFI16:
movl $0, %esi
call _uwind_to_main
addl $20, %esp
popl %esi
leave
ret
LFE10:
.globl _test_edi
_test_edi:
LFB11:
pushl %ebp
LCFI9:
movl %esp, %ebp
LCFI10:
pushl %edi
LCFI11:
subl $20, %esp
LCFI12:
movl $0, %edi
call _uwind_to_main
addl $20, %esp
popl %edi
leave
ret
LFE11:
.globl _test_ebx_esi
_test_ebx_esi:
LFB9:
pushl %ebp
LCFI17:
movl %esp, %ebp
LCFI18:
subl $24, %esp
LCFI19:
movl %ebx, -8(%ebp)
LCFI20:
movl %esi, -4(%ebp)
LCFI21:
movl $0, %ebx
movl $0, %esi
call _uwind_to_main
movl -8(%ebp), %ebx
movl -4(%ebp), %esi
leave
ret
LFE9:
.globl _test_esi_edi
_test_esi_edi:
LFB8:
pushl %ebp
LCFI22:
movl %esp, %ebp
LCFI23:
subl $24, %esp
LCFI24:
movl %esi, -8(%ebp)
LCFI25:
movl %edi, -4(%ebp)
LCFI26:
movl $0, %edi
movl $0, %esi
call _uwind_to_main
movl -8(%ebp), %esi
movl -4(%ebp), %edi
leave
ret
LFE8:
.globl _test_ebx_edi
_test_ebx_edi:
LFB91:
pushl %ebp
LCFI171:
movl %esp, %ebp
LCFI181:
subl $24, %esp
LCFI191:
movl %ebx, -8(%ebp)
LCFI201:
movl %edi, -4(%ebp)
LCFI211:
movl $0, %ebx
movl $0, %edi
call _uwind_to_main
movl -8(%ebp), %ebx
movl -4(%ebp), %edi
leave
ret
LFE91:
.globl _test_ebx_esi_edi
_test_ebx_esi_edi:
LFB7:
pushl %ebp
LCFI27:
movl %esp, %ebp
LCFI28:
subl $40, %esp
LCFI29:
movl %ebx, -12(%ebp)
LCFI30:
movl %esi, -8(%ebp)
LCFI31:
movl %edi, -4(%ebp)
LCFI32:
movl $0, %ebx
movl $0, %edi
movl $0, %esi
call _uwind_to_main
movl -12(%ebp), %ebx
movl -8(%ebp), %esi
movl -4(%ebp), %edi
leave
ret
LFE7:
.globl _test_edi_esi_ebx
_test_edi_esi_ebx:
LFB7a:
pushl %ebp
LCFI27a:
movl %esp, %ebp
LCFI28a:
subl $40, %esp
LCFI29a:
movl %edi, -12(%ebp)
LCFI30a:
movl %esi, -8(%ebp)
LCFI31a:
movl %ebx, -4(%ebp)
LCFI32a:
movl $0, %ebx
movl $0, %esi
movl $0, %edi
call _uwind_to_main
movl -12(%ebp), %edi
movl -8(%ebp), %esi
movl -4(%ebp), %ebx
leave
ret
LFE7a:
.globl _test_pad_ebx_edi
_test_pad_ebx_edi:
LFB91a:
pushl %ebp
LCFI171a:
movl %esp, %ebp
LCFI181a:
subl $88, %esp
LCFI191a:
movl %ebx, -72(%ebp)
LCFI201a:
movl %edi, -68(%ebp)
LCFI211a:
movl $0, %ebx
movl $0, %edi
call _uwind_to_main
movl -72(%ebp), %ebx
movl -68(%ebp), %edi
leave
ret
LFE91a:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 # Length of Common Information Entry
LSCIE1:
.long 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
.byte 0x7c # sleb128 -4; CIE Data Alignment Factor
.byte 0x8 # CIE RA Column
.byte 0x1 # uleb128 0x1; Augmentation size
.byte 0x10 # FDE Encoding (pcrel)
.byte 0xc # DW_CFA_def_cfa
.byte 0x5 # uleb128 0x5
.byte 0x4 # uleb128 0x4
.byte 0x88 # DW_CFA_offset, column 0x8
.byte 0x1 # uleb128 0x1
.byte 0x88 # DW_CFA_offset, column 0x8 // duplicate save in CIE means disable compact unwind encoding
.byte 0x1 # uleb128 0x1
.align 2
LECIE1:
.globl _test_no_reg.eh
_test_no_reg.eh:
LSFDE5:
.set L$set$6,LEFDE5-LASFDE5
.long L$set$6 # FDE Length
LASFDE5:
.long LASFDE5-EH_frame1 # FDE CIE offset
.long LFB12-. # FDE initial location
.set L$set$7,LFE12-LFB12
.long L$set$7 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$8,LCFI6-LFB12
.long L$set$8
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$9,LCFI7-LCFI6
.long L$set$9
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.align 2
LEFDE5:
.globl _test_ebx.eh
_test_ebx.eh:
LSFDE3:
.set L$set$1,LEFDE3-LASFDE3
.long L$set$1 # FDE Length
LASFDE3:
.long LASFDE3-EH_frame1 # FDE CIE offset
.long LFB13-. # FDE initial location
.set L$set$2,LFE13-LFB13
.long L$set$2 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$3,LCFI2-LFB13
.long L$set$3
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$4,LCFI3-LCFI2
.long L$set$4
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$5,LCFI5-LCFI3
.long L$set$5
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.align 2
LEFDE3:
.globl _test_esi.eh
_test_esi.eh:
LSFDE9:
.set L$set$15,LEFDE9-LASFDE9
.long L$set$15 # FDE Length
LASFDE9:
.long LASFDE9-EH_frame1 # FDE CIE offset
.long LFB10-. # FDE initial location
.set L$set$16,LFE10-LFB10
.long L$set$16 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$17,LCFI13-LFB10
.long L$set$17
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$18,LCFI14-LCFI13
.long L$set$18
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$19,LCFI16-LCFI14
.long L$set$19
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x3 # uleb128 0x3
.align 2
LEFDE9:
.globl _test_edi.eh
_test_edi.eh:
LSFDE10:
.set L$set$15a,LEFDE10-LASFDE10
.long L$set$15a # FDE Length
LASFDE10:
.long LASFDE10-EH_frame1 # FDE CIE offset
.long LFB11-. # FDE initial location
.set L$set$16a,LFE11-LFB11
.long L$set$16a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$17a,LCFI9-LFB11
.long L$set$17a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$18a,LCFI10-LCFI9
.long L$set$18a
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$19a,LCFI12-LCFI10
.long L$set$19a
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.align 2
LEFDE10:
.globl _test_ebx_esi.eh
_test_ebx_esi.eh:
LSFDE11:
.set L$set$20,LEFDE11-LASFDE11
.long L$set$20 # FDE Length
LASFDE11:
.long LASFDE11-EH_frame1 # FDE CIE offset
.long LFB9-. # FDE initial location
.set L$set$21,LFE9-LFB9
.long L$set$21 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$22,LCFI17-LFB9
.long L$set$22
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$23,LCFI18-LCFI17
.long L$set$23
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$24,LCFI21-LCFI18
.long L$set$24
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x3 # uleb128 0x3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 2
LEFDE11:
.globl _test_esi_edi.eh
_test_esi_edi.eh:
LSFDE13:
.set L$set$25,LEFDE13-LASFDE13
.long L$set$25 # FDE Length
LASFDE13:
.long LASFDE13-EH_frame1 # FDE CIE offset
.long LFB8-. # FDE initial location
.set L$set$26,LFE8-LFB8
.long L$set$26 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$27,LCFI22-LFB8
.long L$set$27
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$28,LCFI23-LCFI22
.long L$set$28
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$29,LCFI26-LCFI23
.long L$set$29
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.align 2
LEFDE13:
.globl _test_ebx_edi.eh
_test_ebx_edi.eh:
LSFDE111:
.set L$set$20a,LEFDE11-LASFDE11
.long L$set$20a # FDE Length
LASFDE111:
.long LASFDE111-EH_frame1 # FDE CIE offset
.long LFB91-. # FDE initial location
.set L$set$21a,LFE91-LFB91
.long L$set$21a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$22a,LCFI171-LFB91
.long L$set$22a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$23a,LCFI181-LCFI171
.long L$set$23a
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$24a,LCFI211-LCFI181
.long L$set$24a
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 2
LEFDE111:
.globl _test_ebx_esi_edi.eh
_test_ebx_esi_edi.eh:
LSFDE15:
.set L$set$30,LEFDE15-LASFDE15
.long L$set$30 # FDE Length
LASFDE15:
.long LASFDE15-EH_frame1 # FDE CIE offset
.long LFB7-. # FDE initial location
.set L$set$31,LFE7-LFB7
.long L$set$31 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$32,LCFI27-LFB7
.long L$set$32
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$33,LCFI28-LCFI27
.long L$set$33
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$34,LCFI32-LCFI28
.long L$set$34
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x5 # uleb128 0x5
.align 2
LEFDE15:
.globl _test_edi_esi_ebx.eh
_test_edi_esi_ebx.eh:
LSFDE15a:
.set L$set$30a,LEFDE15a-LASFDE15a
.long L$set$30a # FDE Length
LASFDE15a:
.long LASFDE15a-EH_frame1 # FDE CIE offset
.long LFB7a-. # FDE initial location
.set L$set$31a,LFE7a-LFB7a
.long L$set$31a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$32a,LCFI27a-LFB7a
.long L$set$32a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$33a,LCFI28a-LCFI27a
.long L$set$33a
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$34a,LCFI32a-LCFI28a
.long L$set$34a
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x5 # uleb128 0x5
.align 2
LEFDE15a:
.globl _test_pad_ebx_edi.eh
_test_pad_ebx_edi.eh:
LSFDE111a:
.set L$set$20b,LEFDE111a-LASFDE111a
.long L$set$20b # FDE Length
LASFDE111a:
.long LASFDE111a-EH_frame1 # FDE CIE offset
.long LFB91a-. # FDE initial location
.set L$set$21b,LFE91a-LFB91a
.long L$set$21b # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$22b,LCFI171a-LFB91a
.long L$set$22b
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$23b,LCFI181a-LCFI171a
.long L$set$23b
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$24b,LCFI211a-LCFI181a
.long L$set$24b
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x13 # uleb128 0x13
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x14 # uleb128 0x14
.align 2
LEFDE111a:
.subsections_via_symbols

View File

@ -0,0 +1,671 @@
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -DUSE_COMPACT_UNWIND=1
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -DUSE_EH_FRAME=1
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -DUSE_COMPACT_UNWIND=1 -DUSE_EH_FRAME=1
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -DUSE_EH_FRAME=1 -Wl,-no_compact_unwind
.data
.globl _unwind_tester_list
_unwind_tester_list:
.long _test_no_reg
.long _test_ebx
.long _test_esi
.long _test_edi
.long _test_ebx_esi
.long _test_esi_edi
.long _test_ebx_edi
.long _test_ebx_esi_edi
.long _test_edi_esi_ebx
.long _test_pad_ebx_edi
.long 0
.text
.globl _test_ebx
_test_ebx:
LFB13:
pushl %ebp
LCFI2:
movl %esp, %ebp
LCFI3:
pushl %ebx
LCFI4:
subl $20, %esp
LCFI5:
movl $0, %ebx
call _uwind_to_main
addl $20, %esp
popl %ebx
leave
ret
LFE13:
.globl _test_no_reg
_test_no_reg:
LFB12:
pushl %ebp
LCFI6:
movl %esp, %ebp
LCFI7:
subl $24, %esp
LCFI8:
call _uwind_to_main
leave
ret
LFE12:
.globl _test_esi
_test_esi:
LFB10:
pushl %ebp
LCFI13:
movl %esp, %ebp
LCFI14:
pushl %esi
LCFI15:
subl $20, %esp
LCFI16:
movl $0, %esi
call _uwind_to_main
addl $20, %esp
popl %esi
leave
ret
LFE10:
.globl _test_edi
_test_edi:
LFB11:
pushl %ebp
LCFI9:
movl %esp, %ebp
LCFI10:
pushl %edi
LCFI11:
subl $20, %esp
LCFI12:
movl $0, %edi
call _uwind_to_main
addl $20, %esp
popl %edi
leave
ret
LFE11:
.globl _test_ebx_esi
_test_ebx_esi:
LFB9:
pushl %ebp
LCFI17:
movl %esp, %ebp
LCFI18:
subl $24, %esp
LCFI19:
movl %ebx, -8(%ebp)
LCFI20:
movl %esi, -4(%ebp)
LCFI21:
movl $0, %ebx
movl $0, %esi
call _uwind_to_main
movl -8(%ebp), %ebx
movl -4(%ebp), %esi
leave
ret
LFE9:
.globl _test_esi_edi
_test_esi_edi:
LFB8:
pushl %ebp
LCFI22:
movl %esp, %ebp
LCFI23:
subl $24, %esp
LCFI24:
movl %esi, -8(%ebp)
LCFI25:
movl %edi, -4(%ebp)
LCFI26:
movl $0, %edi
movl $0, %esi
call _uwind_to_main
movl -8(%ebp), %esi
movl -4(%ebp), %edi
leave
ret
LFE8:
.globl _test_ebx_edi
_test_ebx_edi:
LFB91:
pushl %ebp
LCFI171:
movl %esp, %ebp
LCFI181:
subl $24, %esp
LCFI191:
movl %ebx, -8(%ebp)
LCFI201:
movl %edi, -4(%ebp)
LCFI211:
movl $0, %ebx
movl $0, %edi
call _uwind_to_main
movl -8(%ebp), %ebx
movl -4(%ebp), %edi
leave
ret
LFE91:
.globl _test_ebx_esi_edi
_test_ebx_esi_edi:
LFB7:
pushl %ebp
LCFI27:
movl %esp, %ebp
LCFI28:
subl $40, %esp
LCFI29:
movl %ebx, -12(%ebp)
LCFI30:
movl %esi, -8(%ebp)
LCFI31:
movl %edi, -4(%ebp)
LCFI32:
movl $0, %ebx
movl $0, %edi
movl $0, %esi
call _uwind_to_main
movl -12(%ebp), %ebx
movl -8(%ebp), %esi
movl -4(%ebp), %edi
leave
ret
LFE7:
.globl _test_edi_esi_ebx
_test_edi_esi_ebx:
LFB7a:
pushl %ebp
LCFI27a:
movl %esp, %ebp
LCFI28a:
subl $40, %esp
LCFI29a:
movl %edi, -12(%ebp)
LCFI30a:
movl %esi, -8(%ebp)
LCFI31a:
movl %ebx, -4(%ebp)
LCFI32a:
movl $0, %ebx
movl $0, %esi
movl $0, %edi
call _uwind_to_main
movl -12(%ebp), %edi
movl -8(%ebp), %esi
movl -4(%ebp), %ebx
leave
ret
LFE7a:
.globl _test_pad_ebx_edi
_test_pad_ebx_edi:
LFB91a:
pushl %ebp
LCFI171a:
movl %esp, %ebp
LCFI181a:
subl $88, %esp
LCFI191a:
movl %ebx, -72(%ebp)
LCFI201a:
movl %edi, -68(%ebp)
LCFI211a:
movl $0, %ebx
movl $0, %edi
call _uwind_to_main
movl -72(%ebp), %ebx
movl -68(%ebp), %edi
leave
ret
LFE91a:
#if USE_EH_FRAME
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 # Length of Common Information Entry
LSCIE1:
.long 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
.byte 0x7c # sleb128 -4; CIE Data Alignment Factor
.byte 0x8 # CIE RA Column
.byte 0x1 # uleb128 0x1; Augmentation size
.byte 0x10 # FDE Encoding (pcrel)
.byte 0xc # DW_CFA_def_cfa
.byte 0x5 # uleb128 0x5
.byte 0x4 # uleb128 0x4
.byte 0x88 # DW_CFA_offset, column 0x8
.byte 0x1 # uleb128 0x1
.align 2
LECIE1:
.globl _test_no_reg.eh
_test_no_reg.eh:
LSFDE5:
.set L$set$6,LEFDE5-LASFDE5
.long L$set$6 # FDE Length
LASFDE5:
.long LASFDE5-EH_frame1 # FDE CIE offset
.long LFB12-. # FDE initial location
.set L$set$7,LFE12-LFB12
.long L$set$7 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$8,LCFI6-LFB12
.long L$set$8
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$9,LCFI7-LCFI6
.long L$set$9
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.align 2
LEFDE5:
.globl _test_ebx.eh
_test_ebx.eh:
LSFDE3:
.set L$set$1,LEFDE3-LASFDE3
.long L$set$1 # FDE Length
LASFDE3:
.long LASFDE3-EH_frame1 # FDE CIE offset
.long LFB13-. # FDE initial location
.set L$set$2,LFE13-LFB13
.long L$set$2 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$3,LCFI2-LFB13
.long L$set$3
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$4,LCFI3-LCFI2
.long L$set$4
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$5,LCFI5-LCFI3
.long L$set$5
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.align 2
LEFDE3:
.globl _test_esi.eh
_test_esi.eh:
LSFDE9:
.set L$set$15,LEFDE9-LASFDE9
.long L$set$15 # FDE Length
LASFDE9:
.long LASFDE9-EH_frame1 # FDE CIE offset
.long LFB10-. # FDE initial location
.set L$set$16,LFE10-LFB10
.long L$set$16 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$17,LCFI13-LFB10
.long L$set$17
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$18,LCFI14-LCFI13
.long L$set$18
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$19,LCFI16-LCFI14
.long L$set$19
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x3 # uleb128 0x3
.align 2
LEFDE9:
.globl _test_edi.eh
_test_edi.eh:
LSFDE10:
.set L$set$15a,LEFDE10-LASFDE10
.long L$set$15a # FDE Length
LASFDE10:
.long LASFDE10-EH_frame1 # FDE CIE offset
.long LFB11-. # FDE initial location
.set L$set$16a,LFE11-LFB11
.long L$set$16a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$17a,LCFI9-LFB11
.long L$set$17a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$18a,LCFI10-LCFI9
.long L$set$18a
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$19a,LCFI12-LCFI10
.long L$set$19a
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.align 2
LEFDE10:
.globl _test_ebx_esi.eh
_test_ebx_esi.eh:
LSFDE11:
.set L$set$20,LEFDE11-LASFDE11
.long L$set$20 # FDE Length
LASFDE11:
.long LASFDE11-EH_frame1 # FDE CIE offset
.long LFB9-. # FDE initial location
.set L$set$21,LFE9-LFB9
.long L$set$21 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$22,LCFI17-LFB9
.long L$set$22
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$23,LCFI18-LCFI17
.long L$set$23
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$24,LCFI21-LCFI18
.long L$set$24
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x3 # uleb128 0x3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 2
LEFDE11:
.globl _test_esi_edi.eh
_test_esi_edi.eh:
LSFDE13:
.set L$set$25,LEFDE13-LASFDE13
.long L$set$25 # FDE Length
LASFDE13:
.long LASFDE13-EH_frame1 # FDE CIE offset
.long LFB8-. # FDE initial location
.set L$set$26,LFE8-LFB8
.long L$set$26 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$27,LCFI22-LFB8
.long L$set$27
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$28,LCFI23-LCFI22
.long L$set$28
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$29,LCFI26-LCFI23
.long L$set$29
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.align 2
LEFDE13:
.globl _test_ebx_edi.eh
_test_ebx_edi.eh:
LSFDE111:
.set L$set$20a,LEFDE11-LASFDE11
.long L$set$20a # FDE Length
LASFDE111:
.long LASFDE111-EH_frame1 # FDE CIE offset
.long LFB91-. # FDE initial location
.set L$set$21a,LFE91-LFB91
.long L$set$21a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$22a,LCFI171-LFB91
.long L$set$22a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$23a,LCFI181-LCFI171
.long L$set$23a
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$24a,LCFI211-LCFI181
.long L$set$24a
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 2
LEFDE111:
.globl _test_ebx_esi_edi.eh
_test_ebx_esi_edi.eh:
LSFDE15:
.set L$set$30,LEFDE15-LASFDE15
.long L$set$30 # FDE Length
LASFDE15:
.long LASFDE15-EH_frame1 # FDE CIE offset
.long LFB7-. # FDE initial location
.set L$set$31,LFE7-LFB7
.long L$set$31 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$32,LCFI27-LFB7
.long L$set$32
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$33,LCFI28-LCFI27
.long L$set$33
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$34,LCFI32-LCFI28
.long L$set$34
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x5 # uleb128 0x5
.align 2
LEFDE15:
.globl _test_edi_esi_ebx.eh
_test_edi_esi_ebx.eh:
LSFDE15a:
.set L$set$30a,LEFDE15a-LASFDE15a
.long L$set$30a # FDE Length
LASFDE15a:
.long LASFDE15a-EH_frame1 # FDE CIE offset
.long LFB7a-. # FDE initial location
.set L$set$31a,LFE7a-LFB7a
.long L$set$31a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$32a,LCFI27a-LFB7a
.long L$set$32a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$33a,LCFI28a-LCFI27a
.long L$set$33a
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$34a,LCFI32a-LCFI28a
.long L$set$34a
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x5 # uleb128 0x5
.align 2
LEFDE15a:
.globl _test_pad_ebx_edi.eh
_test_pad_ebx_edi.eh:
LSFDE111a:
.set L$set$20b,LEFDE111a-LASFDE111a
.long L$set$20b # FDE Length
LASFDE111a:
.long LASFDE111a-EH_frame1 # FDE CIE offset
.long LFB91a-. # FDE initial location
.set L$set$21b,LFE91a-LFB91a
.long L$set$21b # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$22b,LCFI171a-LFB91a
.long L$set$22b
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$23b,LCFI181a-LCFI171a
.long L$set$23b
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$24b,LCFI211a-LCFI181a
.long L$set$24b
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x13 # uleb128 0x13
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x14 # uleb128 0x14
.align 2
LEFDE111a:
#endif // USE_EH_FRAME
#if USE_COMPACT_UNWIND
.section __LD,__compact_unwind,regular,debug
.long _test_no_reg
.set L101,LFE13-_test_no_reg
.long L101
.long 0x01000000
.long 0
.long 0
.long _test_ebx
.set L102,LFE13-_test_ebx
.long L102
.long 0x01010001
.long 0
.long 0
.long _test_esi
.set L103,LFE10-_test_esi
.long L103
.long 0x01010005
.long 0
.long 0
.long _test_edi
.set L104,LFE11-_test_edi
.long L104
.long 0x01010004
.long 0
.long 0
.long _test_ebx_esi
.set L105,LFE9-_test_ebx_esi
.long L105
.long 0x01020029
.long 0
.long 0
.long _test_esi_edi
.set L106,LFE8-_test_esi_edi
.long L106
.long 0x01020025
.long 0
.long 0
.long _test_ebx_edi
.set L107,LFE91-_test_ebx_edi
.long L107
.long 0x01020021
.long 0
.long 0
.long _test_ebx_esi_edi
.set L108,LFE7-_test_ebx_esi_edi
.long L108
.long 0x01030129
.long 0
.long 0
.long _test_edi_esi_ebx
.set L109,LFE7a-_test_edi_esi_ebx
.long L109
.long 0x0103006C
.long 0
.long 0
.long _test_pad_ebx_edi
.set L110,LFE91a-_test_pad_ebx_edi
.long L110
.long 0x01120021
.long 0
.long 0
#endif // USE_COMPACT_UNWIND
.subsections_via_symbols

View File

@ -0,0 +1,516 @@
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -Wl,-no_compact_unwind
.data
.globl _unwind_tester_list
_unwind_tester_list:
.long _test_no_reg
.long _test_ebx
.long _test_esi
.long _test_edi
.long _test_ebx_esi
.long _test_esi_edi
.long _test_esi_edi_ebp
.long _test_ebx_esi_edi
.long _test_ebx_esi_edi_ebp
.long _test_esi_ebp_ebx_edi
.long 0
.text
.globl _test_ebx
_test_ebx:
LFB13:
pushl %ebx
LCFI0:
subl $24, %esp
LCFI1:
movl $0, %ebx
call _uwind_to_main
addl $24, %esp
popl %ebx
ret
LFE13:
.globl _test_no_reg
_test_no_reg:
LFB12:
subl $28, %esp
LCFI2:
call _uwind_to_main
addl $28, %esp
ret
LFE12:
.globl _test_esi
_test_esi:
LFB10:
pushl %esi
LCFI5:
subl $24, %esp
LCFI6:
movl $0, %esi
call _uwind_to_main
addl $24, %esp
popl %esi
ret
LFE10:
.globl _test_edi
_test_edi:
LFB11:
pushl %edi
LCFI3:
subl $24, %esp
LCFI4:
movl $0, %edi
call _uwind_to_main
addl $24, %esp
popl %edi
ret
LFE11:
.globl _test_ebx_esi
_test_ebx_esi:
LFB9:
subl $28, %esp
LCFI7:
movl %ebx, 20(%esp)
LCFI8:
movl %esi, 24(%esp)
LCFI9:
movl $0, %ebx
movl $0, %esi
call _uwind_to_main
movl 20(%esp), %ebx
movl 24(%esp), %esi
addl $28, %esp
ret
LFE9:
.globl _test_esi_edi
_test_esi_edi:
LFB8:
subl $28, %esp
LCFI10:
movl %esi, 20(%esp)
LCFI11:
movl %edi, 24(%esp)
LCFI12:
movl $0, %esi
movl $0, %edi
call _uwind_to_main
movl 20(%esp), %esi
movl 24(%esp), %edi
addl $28, %esp
ret
LFE8:
.globl _test_ebx_esi_edi
_test_ebx_esi_edi:
LFB7:
subl $28, %esp
LCFI13:
movl %ebx, 16(%esp)
LCFI14:
movl %esi, 20(%esp)
LCFI15:
movl %edi, 24(%esp)
LCFI16:
movl $0, %ebx
movl $0, %esi
movl $0, %edi
call _uwind_to_main
movl 16(%esp), %ebx
movl 20(%esp), %esi
movl 24(%esp), %edi
addl $28, %esp
ret
LFE7:
.globl _test_esi_edi_ebp
_test_esi_edi_ebp:
LFB6:
subl $28, %esp
LCFI17:
movl %esi, 16(%esp)
LCFI18:
movl %edi, 20(%esp)
LCFI19:
movl %ebp, 24(%esp)
LCFI20:
movl $0, %esi
movl $0, %edi
movl $0, %ebp
call _uwind_to_main
movl 16(%esp), %esi
movl 20(%esp), %edi
movl 24(%esp), %ebp
addl $28, %esp
ret
LFE6:
.globl _test_ebx_esi_edi_ebp
_test_ebx_esi_edi_ebp:
LFB5:
subl $60, %esp
LCFI21:
movl %ebx, 44(%esp)
LCFI22:
movl %esi, 48(%esp)
LCFI23:
movl %edi, 52(%esp)
LCFI24:
movl %ebp, 56(%esp)
LCFI25:
movl $0, %ebx
movl $0, %esi
movl $0, %edi
movl $0, %ebp
call _uwind_to_main
movl 44(%esp), %ebx
movl 48(%esp), %esi
movl 52(%esp), %edi
movl 56(%esp), %ebp
addl $60, %esp
ret
LFE5:
.globl _test_esi_ebp_ebx_edi
_test_esi_ebp_ebx_edi:
LFB5a:
subl $60, %esp
LCFI21a:
movl %esi, 44(%esp)
LCFI22a:
movl %ebp, 48(%esp)
LCFI23a:
movl %ebx, 52(%esp)
LCFI24a:
movl %edi, 56(%esp)
LCFI25a:
movl $0, %esi
movl $0, %ebp
movl $0, %ebx
movl $0, %edi
call _uwind_to_main
movl 44(%esp), %esi
movl 48(%esp), %ebp
movl 52(%esp), %ebx
movl 56(%esp), %edi
addl $60, %esp
ret
LFE5a:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 # Length of Common Information Entry
LSCIE1:
.long 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
.byte 0x7c # sleb128 -4; CIE Data Alignment Factor
.byte 0x8 # CIE RA Column
.byte 0x1 # uleb128 0x1; Augmentation size
.byte 0x10 # FDE Encoding (pcrel)
.byte 0xc # DW_CFA_def_cfa
.byte 0x5 # uleb128 0x5
.byte 0x4 # uleb128 0x4
.byte 0x88 # DW_CFA_offset, column 0x8
.byte 0x1 # uleb128 0x1
.align 2
LECIE1:
.globl _test_ebx.eh
_test_ebx.eh:
LSFDE3:
.set L$set$1,LEFDE3-LASFDE3
.long L$set$1 # FDE Length
LASFDE3:
.long LASFDE3-EH_frame1 # FDE CIE offset
.long LFB13-. # FDE initial location
.set L$set$2,LFE13-LFB13
.long L$set$2 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$3,LCFI0-LFB13
.long L$set$3
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$4,LCFI1-LCFI0
.long L$set$4
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x2 # uleb128 0x2
.align 2
LEFDE3:
.globl _test_no_reg.eh
_test_no_reg.eh:
LSFDE5:
.set L$set$5,LEFDE5-LASFDE5
.long L$set$5 # FDE Length
LASFDE5:
.long LASFDE5-EH_frame1 # FDE CIE offset
.long LFB12-. # FDE initial location
.set L$set$6,LFE12-LFB12
.long L$set$6 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$7,LCFI2-LFB12
.long L$set$7
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.align 2
LEFDE5:
.globl _test_esi.eh
_test_esi.eh:
LSFDE9:
.set L$set$12,LEFDE9-LASFDE9
.long L$set$12 # FDE Length
LASFDE9:
.long LASFDE9-EH_frame1 # FDE CIE offset
.long LFB10-. # FDE initial location
.set L$set$13,LFE10-LFB10
.long L$set$13 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$14,LCFI5-LFB10
.long L$set$14
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$15,LCFI6-LCFI5
.long L$set$15
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x2 # uleb128 0x2
.align 2
LEFDE9:
.globl _test_edi.eh
_test_edi.eh:
LSFDE10:
.set L$set$12a,LEFDE10-LASFDE10
.long L$set$12a # FDE Length
LASFDE10:
.long LASFDE10-EH_frame1 # FDE CIE offset
.long LFB11-. # FDE initial location
.set L$set$13a,LFE11-LFB11
.long L$set$13a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$14a,LCFI3-LFB11
.long L$set$14a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$15a,LCFI4-LCFI3
.long L$set$15a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x2 # uleb128 0x2
.align 2
LEFDE10:
.globl _test_ebx_esi.eh
_test_ebx_esi.eh:
LSFDE11:
.set L$set$16,LEFDE11-LASFDE11
.long L$set$16 # FDE Length
LASFDE11:
.long LASFDE11-EH_frame1 # FDE CIE offset
.long LFB9-. # FDE initial location
.set L$set$17,LFE9-LFB9
.long L$set$17 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$18,LCFI7-LFB9
.long L$set$18
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$19,LCFI9-LCFI7
.long L$set$19
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x2 # uleb128 0x2
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.align 2
LEFDE11:
.globl _test_esi_edi.eh
_test_esi_edi.eh:
LSFDE13:
.set L$set$20,LEFDE13-LASFDE13
.long L$set$20 # FDE Length
LASFDE13:
.long LASFDE13-EH_frame1 # FDE CIE offset
.long LFB8-. # FDE initial location
.set L$set$21,LFE8-LFB8
.long L$set$21 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$22,LCFI10-LFB8
.long L$set$22
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$23,LCFI12-LCFI10
.long L$set$23
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x2 # uleb128 0x2
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x3 # uleb128 0x3
.align 2
LEFDE13:
.globl _test_ebx_esi_edi.eh
_test_ebx_esi_edi.eh:
LSFDE15:
.set L$set$24,LEFDE15-LASFDE15
.long L$set$24 # FDE Length
LASFDE15:
.long LASFDE15-EH_frame1 # FDE CIE offset
.long LFB7-. # FDE initial location
.set L$set$25,LFE7-LFB7
.long L$set$25 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$26,LCFI13-LFB7
.long L$set$26
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$27,LCFI16-LCFI13
.long L$set$27
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x2 # uleb128 0x2
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x3 # uleb128 0x3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 2
LEFDE15:
.globl _test_esi_edi_ebp.eh
_test_esi_edi_ebp.eh:
LSFDE17:
.set L$set$28,LEFDE17-LASFDE17
.long L$set$28 # FDE Length
LASFDE17:
.long LASFDE17-EH_frame1 # FDE CIE offset
.long LFB6-. # FDE initial location
.set L$set$29,LFE6-LFB6
.long L$set$29 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$30,LCFI17-LFB6
.long L$set$30
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x20 # uleb128 0x20
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$31,LCFI20-LCFI17
.long L$set$31
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.align 2
LEFDE17:
.globl _test_ebx_esi_edi_ebp.eh
_test_ebx_esi_edi_ebp.eh:
LSFDE19:
.set L$set$32,LEFDE19-LASFDE19
.long L$set$32 # FDE Length
LASFDE19:
.long LASFDE19-EH_frame1 # FDE CIE offset
.long LFB5-. # FDE initial location
.set L$set$33,LFE5-LFB5
.long L$set$33 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$34,LCFI21-LFB5
.long L$set$34
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x40 # uleb128 0x40
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$35,LCFI25-LCFI21
.long L$set$35
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x5 # uleb128 0x5
.align 2
LEFDE19:
.globl _test_esi_ebp_ebx_edi.eh
_test_esi_ebp_ebx_edi.eh:
LSFDE19a:
.set L$set$32a,LEFDE19a-LASFDE19a
.long L$set$32a # FDE Length
LASFDE19a:
.long LASFDE19a-EH_frame1 # FDE CIE offset
.long LFB5a-. # FDE initial location
.set L$set$33a,LFE5a-LFB5a
.long L$set$33a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$34a,LCFI21a-LFB5a
.long L$set$34a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x40 # uleb128 0x40
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$35a,LCFI25a-LCFI21a
.long L$set$35a
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x2 # uleb128 0x2
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x4 # uleb128 0x4
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x5 # uleb128 0x5
.align 2
LEFDE19a:
.subsections_via_symbols

View File

@ -0,0 +1,516 @@
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -Wl,-no_compact_unwind
.data
.globl _unwind_tester_list
_unwind_tester_list:
.long _test_no_reg
.long _test_ebx
.long _test_esi
.long _test_edi
.long _test_ebx_esi
.long _test_esi_edi
.long _test_esi_edi_ebp
.long _test_ebx_esi_edi
.long _test_ebx_esi_ebp
.long _test_ebx_esi_edi_ebp
.long 0
.text
.globl _test_ebx
_test_ebx:
LFB13:
pushl %ebx
LCFI0:
subl $80024, %esp
LCFI1:
movl $0, %ebx
call _uwind_to_main
addl $80024, %esp
popl %ebx
ret
LFE13:
.globl _test_no_reg
_test_no_reg:
LFB12:
subl $80028, %esp
LCFI2:
call _uwind_to_main
addl $80028, %esp
ret
LFE12:
.globl _test_esi
_test_esi:
LFB10:
pushl %esi
LCFI5:
subl $80024, %esp
LCFI6:
movl $0, %esi
call _uwind_to_main
addl $80024, %esp
popl %esi
ret
LFE10:
.globl _test_edi
_test_edi:
LFB11:
pushl %edi
LCFI3:
subl $80024, %esp
LCFI4:
movl $0, %edi
call _uwind_to_main
addl $80024, %esp
popl %edi
ret
LFE11:
.globl _test_ebx_esi
_test_ebx_esi:
LFB9:
nop
subl $80028, %esp
LCFI7:
movl %ebx, 80020(%esp)
LCFI8:
movl %esi, 80024(%esp)
LCFI9:
movl $0, %ebx
movl $0, %esi
call _uwind_to_main
movl 80020(%esp), %ebx
movl 80024(%esp), %esi
addl $80028, %esp
ret
LFE9:
.globl _test_esi_edi
_test_esi_edi:
LFB8:
subl $80028, %esp
LCFI10:
movl %esi, 80020(%esp)
LCFI11:
movl %edi, 80024(%esp)
LCFI12:
movl $0, %esi
movl $0, %edi
call _uwind_to_main
movl 80020(%esp), %esi
movl 80024(%esp), %edi
addl $80028, %esp
ret
LFE8:
.globl _test_ebx_esi_edi
_test_ebx_esi_edi:
LFB7:
subl $80028, %esp
LCFI13:
movl %ebx, 80016(%esp)
LCFI14:
movl %esi, 80020(%esp)
LCFI15:
movl %edi, 80024(%esp)
LCFI16:
movl $0, %ebx
movl $0, %esi
movl $0, %edi
call _uwind_to_main
movl 80016(%esp), %ebx
movl 80020(%esp), %esi
movl 80024(%esp), %edi
addl $80028, %esp
ret
LFE7:
.globl _test_ebx_esi_ebp
_test_ebx_esi_ebp:
LFB7a:
subl $80028, %esp
LCFI13a:
movl %ebx, 80016(%esp)
LCFI14a:
movl %esi, 80020(%esp)
LCFI15a:
movl %ebp, 80024(%esp)
LCFI16a:
movl $0, %ebx
movl $0, %esi
movl $0, %ebp
call _uwind_to_main
movl 80016(%esp), %ebx
movl 80020(%esp), %esi
movl 80024(%esp), %ebp
addl $80028, %esp
ret
LFE7a:
.globl _test_esi_edi_ebp
_test_esi_edi_ebp:
LFB6:
subl $80028, %esp
LCFI17:
movl %esi, 80016(%esp)
LCFI18:
movl %edi, 80020(%esp)
LCFI19:
movl %ebp, 80024(%esp)
LCFI20:
movl $0, %esi
movl $0, %edi
movl $0, %ebp
call _uwind_to_main
movl 80016(%esp), %esi
movl 80020(%esp), %edi
movl 80024(%esp), %ebp
addl $80028, %esp
ret
LFE6:
.globl _test_ebx_esi_edi_ebp
_test_ebx_esi_edi_ebp:
LFB5:
subl $80028, %esp
LCFI21:
movl %ebx, 80012(%esp)
LCFI22:
movl %esi, 80016(%esp)
LCFI23:
movl %edi, 80020(%esp)
LCFI24:
movl %ebp, 80024(%esp)
LCFI25:
movl $0, %ebx
movl $0, %esi
movl $0, %edi
movl $0, %ebp
call _uwind_to_main
movl 80012(%esp), %ebx
movl 80016(%esp), %esi
movl 80020(%esp), %edi
movl 80024(%esp), %ebp
addl $80028, %esp
ret
LFE5:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 # Length of Common Information Entry
LSCIE1:
.long 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
.byte 0x7c # sleb128 -4; CIE Data Alignment Factor
.byte 0x8 # CIE RA Column
.byte 0x1 # uleb128 0x1; Augmentation size
.byte 0x10 # FDE Encoding (pcrel)
.byte 0xc # DW_CFA_def_cfa
.byte 0x5 # uleb128 0x5
.byte 0x4 # uleb128 0x4
.byte 0x88 # DW_CFA_offset, column 0x8
.byte 0x1 # uleb128 0x1
.align 2
LECIE1:
.globl _test_ebx.eh
_test_ebx.eh:
LSFDE3:
.set L$set$1,LEFDE3-LASFDE3
.long L$set$1 # FDE Length
LASFDE3:
.long LASFDE3-EH_frame1 # FDE CIE offset
.long LFB13-. # FDE initial location
.set L$set$2,LFE13-LFB13
.long L$set$2 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$3,LCFI0-LFB13
.long L$set$3
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$4,LCFI1-LCFI0
.long L$set$4
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xf1,0x4 # uleb128 0x138a0
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x2 # uleb128 0x2
.align 2
LEFDE3:
.globl _test_no_reg.eh
_test_no_reg.eh:
LSFDE5:
.set L$set$5,LEFDE5-LASFDE5
.long L$set$5 # FDE Length
LASFDE5:
.long LASFDE5-EH_frame1 # FDE CIE offset
.long LFB12-. # FDE initial location
.set L$set$6,LFE12-LFB12
.long L$set$6 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$7,LCFI2-LFB12
.long L$set$7
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xf1,0x4 # uleb128 0x138a0
.align 2
LEFDE5:
.globl _test_esi.eh
_test_esi.eh:
LSFDE9:
.set L$set$12,LEFDE9-LASFDE9
.long L$set$12 # FDE Length
LASFDE9:
.long LASFDE9-EH_frame1 # FDE CIE offset
.long LFB10-. # FDE initial location
.set L$set$13,LFE10-LFB10
.long L$set$13 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$14,LCFI5-LFB10
.long L$set$14
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$15,LCFI6-LCFI5
.long L$set$15
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xf1,0x4 # uleb128 0x138a0
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x2 # uleb128 0x2
.align 2
LEFDE9:
.globl _test_edi.eh
_test_edi.eh:
LSFDE10:
.set L$set$12a,LEFDE10-LASFDE10
.long L$set$12a # FDE Length
LASFDE10:
.long LASFDE10-EH_frame1 # FDE CIE offset
.long LFB11-. # FDE initial location
.set L$set$13a,LFE11-LFB11
.long L$set$13a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$14a,LCFI3-LFB11
.long L$set$14a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$15a,LCFI4-LCFI3
.long L$set$15a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xf1,0x4 # uleb128 0x138a0
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x2 # uleb128 0x2
.align 2
LEFDE10:
.globl _test_ebx_esi.eh
_test_ebx_esi.eh:
LSFDE11:
.set L$set$16,LEFDE11-LASFDE11
.long L$set$16 # FDE Length
LASFDE11:
.long LASFDE11-EH_frame1 # FDE CIE offset
.long LFB9-. # FDE initial location
.set L$set$17,LFE9-LFB9
.long L$set$17 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$18,LCFI7-LFB9
.long L$set$18
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xf1,0x4 # uleb128 0x138a0
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$19,LCFI9-LCFI7
.long L$set$19
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x2 # uleb128 0x2
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.align 2
LEFDE11:
.globl _test_esi_edi.eh
_test_esi_edi.eh:
LSFDE13:
.set L$set$20,LEFDE13-LASFDE13
.long L$set$20 # FDE Length
LASFDE13:
.long LASFDE13-EH_frame1 # FDE CIE offset
.long LFB8-. # FDE initial location
.set L$set$21,LFE8-LFB8
.long L$set$21 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$22,LCFI10-LFB8
.long L$set$22
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xf1,0x4 # uleb128 0x138a0
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$23,LCFI12-LCFI10
.long L$set$23
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x2 # uleb128 0x2
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x3 # uleb128 0x3
.align 2
LEFDE13:
.globl _test_ebx_esi_edi.eh
_test_ebx_esi_edi.eh:
LSFDE15:
.set L$set$24,LEFDE15-LASFDE15
.long L$set$24 # FDE Length
LASFDE15:
.long LASFDE15-EH_frame1 # FDE CIE offset
.long LFB7-. # FDE initial location
.set L$set$25,LFE7-LFB7
.long L$set$25 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$26,LCFI13-LFB7
.long L$set$26
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xf1,0x4 # uleb128 0x138a0
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$27,LCFI16-LCFI13
.long L$set$27
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x2 # uleb128 0x2
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x3 # uleb128 0x3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 2
LEFDE15:
.globl _test_ebx_esi_ebp.eh
_test_ebx_esi_ebp.eh:
LSFDE15a:
.set L$set$24a,LEFDE15a-LASFDE15a
.long L$set$24a # FDE Length
LASFDE15a:
.long LASFDE15a-EH_frame1 # FDE CIE offset
.long LFB7a-. # FDE initial location
.set L$set$25a,LFE7a-LFB7a
.long L$set$25a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$26a,LCFI13a-LFB7a
.long L$set$26a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xf1,0x4 # uleb128 0x138a0
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$27a,LCFI16a-LCFI13a
.long L$set$27a
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x3 # uleb128 0x3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 2
LEFDE15a:
.globl _test_esi_edi_ebp.eh
_test_esi_edi_ebp.eh:
LSFDE17:
.set L$set$28,LEFDE17-LASFDE17
.long L$set$28 # FDE Length
LASFDE17:
.long LASFDE17-EH_frame1 # FDE CIE offset
.long LFB6-. # FDE initial location
.set L$set$29,LFE6-LFB6
.long L$set$29 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$30,LCFI17-LFB6
.long L$set$30
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xf1,0x4 # uleb128 0x138a0
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$31,LCFI20-LCFI17
.long L$set$31
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.align 2
LEFDE17:
.globl _test_ebx_esi_edi_ebp.eh
_test_ebx_esi_edi_ebp.eh:
LSFDE19:
.set L$set$32,LEFDE19-LASFDE19
.long L$set$32 # FDE Length
LASFDE19:
.long LASFDE19-EH_frame1 # FDE CIE offset
.long LFB5-. # FDE initial location
.set L$set$33,LFE5-LFB5
.long L$set$33 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$34,LCFI21-LFB5
.long L$set$34
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0xa0,0xf1,0x4 # uleb128 0x138a0
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$35,LCFI25-LCFI21
.long L$set$35
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x5 # uleb128 0x5
.align 2
LEFDE19:
.subsections_via_symbols

View File

@ -0,0 +1,330 @@
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions
# TEST-OPTIONS: unwind_test_main.c unwind_test_x86.s -arch i386 -fexceptions -Wl,-no_compact_unwind
.data
.globl _unwind_tester_list
_unwind_tester_list:
.long _test_ebx_wrong_slot
.long _test_esi_in_ebx
.long _test_edi_pad_ebx
.long _test_coal_ebx_esi_edi
.long Ltest_edi_pad_ebx
.long 0
.text
.globl _test_ebx_wrong_slot
_test_ebx_wrong_slot:
LFB13:
pushl %ebp
LCFI2:
movl %esp, %ebp
LCFI3:
subl $4, %esp
pushl %ebx
LCFI4:
subl $16, %esp
LCFI5:
movl $0, %ebx
call _uwind_to_main
addl $16, %esp
popl %ebx
addl $4, %esp
leave
ret
LFE13:
.globl _test_esi_in_ebx
_test_esi_in_ebx:
LFB9:
pushl %ebp
LCFI17:
movl %esp, %ebp
LCFI18:
subl $24, %esp
LCFI19:
movl %ebx, -8(%ebp)
LCFI20:
movl %esi, %ebx
LCFI21:
movl $0, %esi
call _uwind_to_main
movl %ebx, %esi
movl -8(%ebp), %ebx
leave
ret
LFE9:
.globl _test_edi_pad_ebx
_test_edi_pad_ebx:
LFB7a:
pushl %ebp
LCFI27a:
movl %esp, %ebp
LCFI28a:
subl $140, %esp
LCFI29a:
movl %edi, -44(%ebp)
LCFI30a:
LCFI31a:
movl %ebx, -4(%ebp)
LCFI32a:
movl $0, %ebx
movl $0, %edi
call _uwind_to_main
movl -44(%ebp), %edi
movl -4(%ebp), %ebx
leave
ret
LFE7a:
Ltest_edi_pad_ebx:
LFB7b:
pushl %ebp
LCFI27b:
movl %esp, %ebp
LCFI28b:
subl $140, %esp
LCFI29b:
movl %edi, -44(%ebp)
LCFI30b:
LCFI31b:
movl %ebx, -4(%ebp)
LCFI32b:
movl $0, %ebx
movl $0, %edi
call _uwind_to_main
movl -44(%ebp), %edi
movl -4(%ebp), %ebx
leave
ret
LFE7b:
.section __TEXT,__textcoal_nt,coalesced,pure_instructions
.globl _test_coal_ebx_esi_edi
.weak_definition _test_coal_ebx_esi_edi
_test_coal_ebx_esi_edi:
LFB7:
pushl %ebp
LCFI27:
movl %esp, %ebp
LCFI28:
subl $40, %esp
LCFI29:
movl %ebx, -12(%ebp)
LCFI30:
movl %esi, -8(%ebp)
LCFI31:
movl %edi, -4(%ebp)
LCFI32:
movl $0, %ebx
movl $0, %edi
movl $0, %esi
call _uwind_to_main
movl -12(%ebp), %ebx
movl -8(%ebp), %esi
movl -4(%ebp), %edi
leave
ret
LFE7:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0 # Length of Common Information Entry
LSCIE1:
.long 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
.ascii "zR\0" # CIE Augmentation
.byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
.byte 0x7c # sleb128 -4; CIE Data Alignment Factor
.byte 0x8 # CIE RA Column
.byte 0x1 # uleb128 0x1; Augmentation size
.byte 0x10 # FDE Encoding (pcrel)
.byte 0xc # DW_CFA_def_cfa
.byte 0x5 # uleb128 0x5
.byte 0x4 # uleb128 0x4
.byte 0x88 # DW_CFA_offset, column 0x8
.byte 0x1 # uleb128 0x1
.align 2
LECIE1:
.globl _test_ebx_wrong_slot.eh
_test_ebx_wrong_slot.eh:
LSFDE3:
.set L$set$1,LEFDE3-LASFDE3
.long L$set$1 # FDE Length
LASFDE3:
.long LASFDE3-EH_frame1 # FDE CIE offset
.long LFB13-. # FDE initial location
.set L$set$2,LFE13-LFB13
.long L$set$2 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$3,LCFI2-LFB13
.long L$set$3
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$4,LCFI3-LCFI2
.long L$set$4
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$5,LCFI5-LCFI3
.long L$set$5
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 2
LEFDE3:
.globl _test_esi_in_ebx.eh
_test_esi_in_ebx.eh:
LSFDE11:
.set L$set$20,LEFDE11-LASFDE11
.long L$set$20 # FDE Length
LASFDE11:
.long LASFDE11-EH_frame1 # FDE CIE offset
.long LFB9-. # FDE initial location
.set L$set$21,LFE9-LFB9
.long L$set$21 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$22,LCFI17-LFB9
.long L$set$22
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$23,LCFI18-LCFI17
.long L$set$23
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$24,LCFI21-LCFI18
.long L$set$24
.byte 0x09, 0x06, 0x03 # DW_CFA_register 6, 3
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x4 # uleb128 0x4
.align 2
LEFDE11:
.globl _test_edi_pad_ebx.eh
_test_edi_pad_ebx.eh:
LSFDE15a:
.set L$set$30,LEFDE15a-LASFDE15a
.long L$set$30 # FDE Length
LASFDE15a:
.long LASFDE15a-EH_frame1 # FDE CIE offset
.long LFB7a-. # FDE initial location
.set L$set$31,LFE7a-LFB7a
.long L$set$31 # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$32,LCFI27a-LFB7a
.long L$set$32
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$33,LCFI28a-LCFI27a
.long L$set$33
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$34,LCFI32a-LCFI28a
.long L$set$34
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0xD # uleb128 0xD
.align 2
LEFDE15a:
ltest_edi_pad_ebx.eh:
LSFDE15b:
.set L$set$30a,LEFDE15b-LASFDE15b
.long L$set$30a # FDE Length
LASFDE15b:
.long LASFDE15b-EH_frame1 # FDE CIE offset
.long LFB7b-. # FDE initial location
.set L$set$31a,LFE7b-LFB7b
.long L$set$31a # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$32a,LCFI27b-LFB7b
.long L$set$32a
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$33a,LCFI28b-LCFI27b
.long L$set$33a
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$34a,LCFI32b-LCFI28b
.long L$set$34a
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x3 # uleb128 0x3
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0xD # uleb128 0xD
.align 2
LEFDE15b:
.globl _test_coal_ebx_esi_edi.eh
_test_coal_ebx_esi_edi.eh:
LSFDE15:
.set L$set$30b,LEFDE15-LASFDE15
.long L$set$30b # FDE Length
LASFDE15:
.long LASFDE15-EH_frame1 # FDE CIE offset
.long LFB7-. # FDE initial location
.set L$set$31b,LFE7-LFB7
.long L$set$31b # FDE address range
.byte 0x0 # uleb128 0x0; Augmentation size
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$32b,LCFI27-LFB7
.long L$set$32b
.byte 0xe # DW_CFA_def_cfa_offset
.byte 0x8 # uleb128 0x8
.byte 0x84 # DW_CFA_offset, column 0x4
.byte 0x2 # uleb128 0x2
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$33b,LCFI28-LCFI27
.long L$set$33b
.byte 0xd # DW_CFA_def_cfa_register
.byte 0x4 # uleb128 0x4
.byte 0x4 # DW_CFA_advance_loc4
.set L$set$34b,LCFI32-LCFI28
.long L$set$34b
.byte 0x87 # DW_CFA_offset, column 0x7
.byte 0x3 # uleb128 0x3
.byte 0x86 # DW_CFA_offset, column 0x6
.byte 0x4 # uleb128 0x4
.byte 0x83 # DW_CFA_offset, column 0x3
.byte 0x5 # uleb128 0x5
.align 2
LEFDE15:
.subsections_via_symbols