Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -103,6 +103,7 @@ option(LIBUNWIND_ENABLE_PEDANTIC "Compile with pedantic enabled." ON) option(LIBUNWIND_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF) option(LIBUNWIND_ENABLE_SHARED "Build libunwind as a shared library." ON) +option(LIBUNWIND_ENABLE_CROSS_UNWINDING "Enable cross-platform unwinding support." ON) set(LIBUNWIND_GCC_TOOLCHAIN "" CACHE STRING "GCC toolchain for cross compiling.") set(LIBUNWIND_SYSROOT "" CACHE STRING "Sysroot for cross compiling.") @@ -202,6 +203,11 @@ endif () endif () +# Cross-unwinding +if (NOT LIBUNWIND_ENABLE_CROSS_UNWINDING) + list(APPEND LIBUNWIND_COMPILE_FLAGS -D_LIBUNWIND_IS_NATIVE_ONLY) +endif () + # This is the _ONLY_ place where add_definitions is called. if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) Index: include/__libunwind_config.h =================================================================== --- include/__libunwind_config.h +++ include/__libunwind_config.h @@ -17,4 +17,43 @@ #define _LIBUNWIND_ARM_EHABI 0 #endif +#if defined(_LIBUNWIND_IS_NATIVE_ONLY) +# if defined(__i386__) +# define _LIBUNWIND_TARGET_I386 1 +# define _LIBUNWIND_CONTEXT_SIZE 8 +# define _LIBUNWIND_CURSOR_SIZE 19 +# elif defined(__x86_64__) +# define _LIBUNWIND_TARGET_X86_64 1 +# define _LIBUNWIND_CONTEXT_SIZE 21 +# define _LIBUNWIND_CURSOR_SIZE 33 +# elif defined(__ppc__) +# define _LIBUNWIND_TARGET_PPC 1 +# define _LIBUNWIND_CONTEXT_SIZE 117 +# define _LIBUNWIND_CURSOR_SIZE 128 +# elif defined(__aarch64__) +# define _LIBUNWIND_TARGET_AARCH64 1 +# define _LIBUNWIND_CONTEXT_SIZE 66 +# define _LIBUNWIND_CURSOR_SIZE 78 +# elif defined(__arm__) +# define _LIBUNWIND_TARGET_ARM 1 +# define _LIBUNWIND_CONTEXT_SIZE 60 +# define _LIBUNWIND_CURSOR_SIZE 67 +# elif defined(__or1k__) +# define _LIBUNWIND_TARGET_OR1K 1 +# define _LIBUNWIND_CONTEXT_SIZE 16 +# define _LIBUNWIND_CURSOR_SIZE 28 +# else +# error "Unsupported architecture." +# endif +#else // !_LIBUNWIND_IS_NATIVE_ONLY +# define _LIBUNWIND_TARGET_I386 1 +# define _LIBUNWIND_TARGET_X86_64 1 +# define _LIBUNWIND_TARGET_PPC 1 +# define _LIBUNWIND_TARGET_AARCH64 1 +# define _LIBUNWIND_TARGET_ARM 1 +# define _LIBUNWIND_TARGET_OR1K 1 +# define _LIBUNWIND_CONTEXT_SIZE 128 +# define _LIBUNWIND_CURSOR_SIZE 140 +#endif // _LIBUNWIND_IS_NATIVE_ONLY + #endif // ____LIBUNWIND_CONFIG_H__ Index: include/libunwind.h =================================================================== --- include/libunwind.h +++ include/libunwind.h @@ -46,12 +46,12 @@ }; struct unw_context_t { - uint64_t data[128]; + uint64_t data[_LIBUNWIND_CONTEXT_SIZE]; }; typedef struct unw_context_t unw_context_t; struct unw_cursor_t { - uint64_t data[140]; + uint64_t data[_LIBUNWIND_CURSOR_SIZE]; }; typedef struct unw_cursor_t unw_cursor_t; Index: src/CompactUnwinder.hpp =================================================================== --- src/CompactUnwinder.hpp +++ src/CompactUnwinder.hpp @@ -27,6 +27,7 @@ namespace libunwind { +#if defined(_LIBUNWIND_TARGET_I386) /// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka /// unwind) by modifying a Registers_x86 register set template @@ -255,8 +256,10 @@ // old esp is before return address registers.setSP((uint32_t)returnAddressLocation + 4); } +#endif // _LIBUNWIND_TARGET_I386 +#if defined(_LIBUNWIND_TARGET_X86_64) /// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka /// unwind) by modifying a Registers_x86_64 register set template @@ -484,9 +487,11 @@ // old esp is before return address registers.setSP(returnAddressLocation + 8); } +#endif // _LIBUNWIND_TARGET_X86_64 +#if defined(_LIBUNWIND_TARGET_AARCH64) /// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka /// unwind) by modifying a Registers_arm64 register set template @@ -686,6 +691,7 @@ return UNW_STEP_SUCCESS; } +#endif // _LIBUNWIND_TARGET_AARCH64 } // namespace libunwind Index: src/Registers.hpp =================================================================== --- src/Registers.hpp +++ src/Registers.hpp @@ -25,6 +25,7 @@ struct v128 { uint32_t vec[4]; }; +#if defined(_LIBUNWIND_TARGET_I386) /// Registers_x86 holds the register state of a thread in a 32-bit intel /// process. class _LIBUNWIND_HIDDEN Registers_x86 { @@ -86,8 +87,8 @@ }; inline Registers_x86::Registers_x86(const void *registers) { - static_assert(sizeof(Registers_x86) < sizeof(unw_context_t), - "x86 registers do not fit into unw_context_t"); + static_assert(check_fit::does_fit, + "x86 registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); } @@ -211,8 +212,10 @@ inline void Registers_x86::setVectorRegister(int, v128) { _LIBUNWIND_ABORT("no x86 vector registers"); } +#endif // _LIBUNWIND_TARGET_I386 +#if defined(_LIBUNWIND_TARGET_X86_64) /// Registers_x86_64 holds the register state of a thread in a 64-bit intel /// process. class _LIBUNWIND_HIDDEN Registers_x86_64 { @@ -278,8 +281,8 @@ }; inline Registers_x86_64::Registers_x86_64(const void *registers) { - static_assert(sizeof(Registers_x86_64) < sizeof(unw_context_t), - "x86_64 registers do not fit into unw_context_t"); + static_assert(check_fit::does_fit, + "x86_64 registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); } @@ -459,8 +462,10 @@ inline void Registers_x86_64::setVectorRegister(int, v128) { _LIBUNWIND_ABORT("no x86_64 vector registers"); } +#endif // _LIBUNWIND_TARGET_X86_64 +#if defined(_LIBUNWIND_TARGET_PPC) /// Registers_ppc holds the register state of a thread in a 32-bit PowerPC /// process. class _LIBUNWIND_HIDDEN Registers_ppc { @@ -543,8 +548,8 @@ }; inline Registers_ppc::Registers_ppc(const void *registers) { - static_assert(sizeof(Registers_ppc) < sizeof(unw_context_t), - "ppc registers do not fit into unw_context_t"); + static_assert(check_fit::does_fit, + "ppc registers do not fit into unw_context_t"); memcpy(&_registers, static_cast(registers), sizeof(_registers)); static_assert(sizeof(ppc_thread_state_t) == 160, @@ -1023,8 +1028,10 @@ } } +#endif // _LIBUNWIND_TARGET_PPC +#if defined(_LIBUNWIND_TARGET_AARCH64) /// Registers_arm64 holds the register state of a thread in a 64-bit arm /// process. class _LIBUNWIND_HIDDEN Registers_arm64 { @@ -1071,8 +1078,8 @@ }; inline Registers_arm64::Registers_arm64(const void *registers) { - static_assert(sizeof(Registers_arm64) < sizeof(unw_context_t), - "arm64 registers do not fit into unw_context_t"); + static_assert(check_fit::does_fit, + "arm64 registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); static_assert(sizeof(GPRs) == 0x110, "expected VFP registers to be at offset 272"); @@ -1289,7 +1296,9 @@ inline void Registers_arm64::setVectorRegister(int, v128) { _LIBUNWIND_ABORT("no arm64 vector register support yet"); } +#endif // _LIBUNWIND_TARGET_AARCH64 +#if defined(_LIBUNWIND_TARGET_ARM) /// Registers_arm holds the register state of a thread in a 32-bit arm /// process. /// @@ -1395,8 +1404,8 @@ _saved_vfp_d16_d31(false), _saved_iwmmx(false), _saved_iwmmx_control(false) { - static_assert(sizeof(Registers_arm) < sizeof(unw_context_t), - "arm registers do not fit into unw_context_t"); + static_assert(check_fit::does_fit, + "arm registers do not fit into unw_context_t"); // See unw_getcontext() note about data. memcpy(&_registers, registers, sizeof(_registers)); memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); @@ -1711,6 +1720,10 @@ inline void Registers_arm::setVectorRegister(int, v128) { _LIBUNWIND_ABORT("ARM vector support not implemented"); } +#endif // _LIBUNWIND_TARGET_ARM + + +#if defined(_LIBUNWIND_TARGET_OR1K) /// Registers_or1k holds the register state of a thread in an OpenRISC1000 /// process. class _LIBUNWIND_HIDDEN Registers_or1k { @@ -1745,8 +1758,8 @@ }; inline Registers_or1k::Registers_or1k(const void *registers) { - static_assert(sizeof(Registers_or1k) < sizeof(unw_context_t), - "or1k registers do not fit into unw_context_t"); + static_assert(check_fit::does_fit, + "or1k registers do not fit into unw_context_t"); memcpy(&_registers, static_cast(registers), sizeof(_registers)); } @@ -1893,6 +1906,7 @@ } } +#endif // _LIBUNWIND_TARGET_OR1K } // namespace libunwind #endif // __REGISTERS_HPP__ Index: src/UnwindCursor.hpp =================================================================== --- src/UnwindCursor.hpp +++ src/UnwindCursor.hpp @@ -481,30 +481,39 @@ return stepWithCompactEncoding(dummy); } +#if defined(_LIBUNWIND_TARGET_X86_64) int stepWithCompactEncoding(Registers_x86_64 &) { return CompactUnwinder_x86_64::stepWithCompactEncoding( _info.format, _info.start_ip, _addressSpace, _registers); } +#endif +#if defined(_LIBUNWIND_TARGET_I386) int stepWithCompactEncoding(Registers_x86 &) { return CompactUnwinder_x86::stepWithCompactEncoding( _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers); } +#endif +#if defined(_LIBUNWIND_TARGET_PPC) int stepWithCompactEncoding(Registers_ppc &) { return UNW_EINVAL; } +#endif +#if defined(_LIBUNWIND_TARGET_AARCH64) int stepWithCompactEncoding(Registers_arm64 &) { return CompactUnwinder_arm64::stepWithCompactEncoding( _info.format, _info.start_ip, _addressSpace, _registers); } +#endif bool compactSaysUseDwarf(uint32_t *offset=NULL) const { R dummy; return compactSaysUseDwarf(dummy, offset); } +#if defined(_LIBUNWIND_TARGET_X86_64) bool compactSaysUseDwarf(Registers_x86_64 &, uint32_t *offset) const { if ((_info.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF) { if (offset) @@ -513,7 +522,9 @@ } return false; } +#endif +#if defined(_LIBUNWIND_TARGET_I386) bool compactSaysUseDwarf(Registers_x86 &, uint32_t *offset) const { if ((_info.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF) { if (offset) @@ -522,11 +533,15 @@ } return false; } +#endif +#if defined(_LIBUNWIND_TARGET_PPC) bool compactSaysUseDwarf(Registers_ppc &, uint32_t *) const { return true; } +#endif +#if defined(_LIBUNWIND_TARGET_AARCH64) bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const { if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) { if (offset) @@ -535,6 +550,7 @@ } return false; } +#endif #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND #if _LIBUNWIND_SUPPORT_DWARF_UNWIND @@ -543,25 +559,35 @@ return dwarfEncoding(dummy); } +#if defined(_LIBUNWIND_TARGET_X86_64) compact_unwind_encoding_t dwarfEncoding(Registers_x86_64 &) const { return UNWIND_X86_64_MODE_DWARF; } +#endif +#if defined(_LIBUNWIND_TARGET_I386) compact_unwind_encoding_t dwarfEncoding(Registers_x86 &) const { return UNWIND_X86_MODE_DWARF; } +#endif +#if defined(_LIBUNWIND_TARGET_PPC) compact_unwind_encoding_t dwarfEncoding(Registers_ppc &) const { return 0; } +#endif +#if defined(_LIBUNWIND_TARGET_AARCH64) compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const { return UNWIND_ARM64_MODE_DWARF; } +#endif +#if defined (_LIBUNWIND_TARGET_OR1K) compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const { return 0; } +#endif #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND @@ -577,7 +603,7 @@ UnwindCursor::UnwindCursor(unw_context_t *context, A &as) : _addressSpace(as), _registers(context), _unwindInfoMissing(false), _isSignalFrame(false) { - static_assert(sizeof(UnwindCursor) < sizeof(unw_cursor_t), + static_assert(check_fit, unw_cursor_t>::does_fit, "UnwindCursor<> does not fit in unw_cursor_t"); memset(&_info, 0, sizeof(_info)); } Index: src/config.h =================================================================== --- src/config.h +++ src/config.h @@ -119,5 +119,25 @@ #define _LIBUNWIND_TRACING_UNWINDING logUnwinding() #endif +#ifdef __cplusplus +// Used to fit UnwindCursor and Registers_xxx types against unw_context_t / +// unw_cursor_t sized memory blocks. +#if defined(_LIBUNWIND_IS_NATIVE_ONLY) +# define COMP_OP == +#else +# define COMP_OP < +#endif +template +struct check_fit { + template + struct blk_count { + static const uint32_t count = + (sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t); + }; + static const bool does_fit = + (blk_count<_Type>::count COMP_OP blk_count<_Mem>::count); +}; +#undef COMP_OP +#endif // __cplusplus #endif // LIBUNWIND_CONFIG_H Index: src/libunwind.cpp =================================================================== --- src/libunwind.cpp +++ src/libunwind.cpp @@ -45,30 +45,27 @@ _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)\n", static_cast(cursor), static_cast(context)); - // Use "placement new" to allocate UnwindCursor in the cursor buffer. #if defined(__i386__) - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); +# define REGISTER_KIND Registers_x86 #elif defined(__x86_64__) - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); +# define REGISTER_KIND Registers_x86_64 #elif defined(__ppc__) - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); -#elif defined(__arm64__) || defined(__aarch64__) - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); +# define REGISTER_KIND Registers_ppc +#elif defined(__aarch64__) +# define REGISTER_KIND Registers_arm64 #elif _LIBUNWIND_ARM_EHABI - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); +# define REGISTER_KIND Registers_arm #elif defined(__or1k__) - new ((void *)cursor) UnwindCursor( - context, LocalAddressSpace::sThisAddressSpace); +# define REGISTER_KIND Registers_or1k #elif defined(__mips__) -#warning The MIPS architecture is not supported. +# warning The MIPS architecture is not supported. #else -#error Architecture not supported +# error Architecture not supported #endif + // Use "placement new" to allocate UnwindCursor in the cursor buffer. + new ((void *)cursor) UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); +#undef REGISTER_KIND AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; co->setInfoBasedOnIPRegister();