From cab73a946eac246eab1a06607928cf6b77de5415 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 4 Sep 2026 07:56:14 +0200 Subject: [PATCH 1/3] fix(native): Detect libunwind ABI from pointer width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Raspberry Pi OS can run a 32-bit armhf userland with a 64-bit kernel. In that configuration, CMake reports aarch64 as the system processor while the compiler emits 32-bit ARM code. Vendored libunwind previously used the system processor for both the processor family and ABI width. It consequently combined ARM symbols with AArch64 DWARF headers and produced this diagnostic: vendor/libunwind/src/dwarf/Gexpr.c: In function ‘_ULarm_dwarf_eval_expr’: vendor/libunwind/include/tdep-aarch64/dwarf-config.h:37:45: error: ‘UNW_AARCH64_V31’ undeclared (first use in this function) vendor/libunwind/src/dwarf/Gexpr.c:359:35: note: in expansion of macro ‘dwarf_to_unw_regnum’ Normalize processor names into x86 and ARM families, then select the concrete architecture and ELF class from the compiler pointer width. This also handles the equivalent 32-bit x86 userland configuration. --- vendor/libunwind/CMakeLists.txt | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/vendor/libunwind/CMakeLists.txt b/vendor/libunwind/CMakeLists.txt index 7de5085c97..6b46e7c9e1 100644 --- a/vendor/libunwind/CMakeLists.txt +++ b/vendor/libunwind/CMakeLists.txt @@ -16,22 +16,27 @@ set(LIBUNWIND_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src") set(LIBUNWIND_INC "${CMAKE_CURRENT_SOURCE_DIR}/include") # Detect architecture -if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64") - set(UNWIND_ARCH "x86_64") - set(UNWIND_ELF "elf64") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|arm64") - set(UNWIND_ARCH "aarch64") - set(UNWIND_ELF "elf64") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i[3-6]86|x86") - set(UNWIND_ARCH "x86") - set(UNWIND_ELF "elf32") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm|ARM)") - set(UNWIND_ARCH "arm") - set(UNWIND_ELF "elf32") +string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" _UNWIND_PROCESSOR) +if(_UNWIND_PROCESSOR MATCHES "^(x86_64|amd64|x64|i[3-6]86|x86)$") + set(_UNWIND_ARCH_32 "x86") + set(_UNWIND_ARCH_64 "x86_64") +elseif(_UNWIND_PROCESSOR MATCHES "^(aarch64|arm64|arm)") + set(_UNWIND_ARCH_32 "arm") + set(_UNWIND_ARCH_64 "aarch64") else() message(FATAL_ERROR "Unsupported architecture for vendored libunwind: ${CMAKE_SYSTEM_PROCESSOR}") endif() +if(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(UNWIND_ARCH "${_UNWIND_ARCH_32}") + set(UNWIND_ELF "elf32") +elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(UNWIND_ARCH "${_UNWIND_ARCH_64}") + set(UNWIND_ELF "elf64") +else() + message(FATAL_ERROR "Unsupported pointer size for vendored libunwind: ${CMAKE_SIZEOF_VOID_P}") +endif() + # Common sources (libunwind_la_SOURCES_common + os sources for Linux) set(UNWIND_COMMON_SOURCES ${LIBUNWIND_SRC}/os-linux.c From 57eadd4fb88e0a429699155c221fcce4f79781f9 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 4 Sep 2026 08:09:51 +0200 Subject: [PATCH 2/3] fix: Build on baseline ARM32 targets Avoid aliasing fixed-width module mapping fields as native pointer and size types in the module finder test. Convert mapped addresses through uintptr_t before widening them to uint64_t. Use nop for CPU relaxation on 32-bit ARM, where the baseline assembler can reject yield as an unsupported instruction. AArch64 continues to use yield. Detect whether 64-bit atomic operations require libatomic and link it when necessary. This supports ARM32 targets where those operations are not provided directly by the compiler's target architecture. This fixes the incompatible pointer type, pointer-to-integer cast, unsupported processor instruction, and unresolved __atomic_load_8 and __atomic_store_8 diagnostics from the ARM32 build. --- CMakeLists.txt | 5 ++++ cmake/utils.cmake | 25 ++++++++++++++++++++ src/modulefinder/sentry_modulefinder_linux.c | 2 +- src/sentry_cpu_relax.h | 4 +++- tests/unit/test_modulefinder.c | 9 +++---- 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 12615fd976..3d3c63e053 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -661,6 +661,11 @@ if(ANDROID) set(_SENTRY_PLATFORM_LIBS "dl" "log") elseif(LINUX) set(_SENTRY_PLATFORM_LIBS "dl" "rt") + sentry_find_atomic_library(_SENTRY_ATOMIC_LIBRARY) + if(_SENTRY_ATOMIC_LIBRARY) + list(APPEND _SENTRY_PLATFORM_LIBS "${_SENTRY_ATOMIC_LIBRARY}") + endif() + unset(_SENTRY_ATOMIC_LIBRARY) elseif(WIN32) if (XBOX) set(_SENTRY_PLATFORM_LIBS "version") diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 3b43ccf4d1..de8e4f3196 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -22,3 +22,28 @@ function(sentry_get_property NAME) endif() set("SENTRY_${NAME}" "${prop}" PARENT_SCOPE) endfunction() + +function(sentry_find_atomic_library OUT_VAR) + include(CheckCSourceCompiles) + include(CMakePushCheckState) + cmake_push_check_state(RESET) + set(ATOMIC_U64_SOURCE " + #include + uint64_t value; + int main(void) { + return (int)__atomic_load_n(&value, __ATOMIC_SEQ_CST); + }") + check_c_source_compiles("${ATOMIC_U64_SOURCE}" SENTRY_HAVE_ATOMIC_U64) + if(SENTRY_HAVE_ATOMIC_U64) + set(ATOMIC_LIBRARY) + else() + set(CMAKE_REQUIRED_LIBRARIES atomic) + check_c_source_compiles("${ATOMIC_U64_SOURCE}" SENTRY_HAVE_ATOMIC_U64_WITH_LIB) + if(NOT SENTRY_HAVE_ATOMIC_U64_WITH_LIB) + message(FATAL_ERROR "64-bit atomic operations are not supported") + endif() + set(ATOMIC_LIBRARY atomic) + endif() + cmake_pop_check_state() + set(${OUT_VAR} "${ATOMIC_LIBRARY}" PARENT_SCOPE) +endfunction() diff --git a/src/modulefinder/sentry_modulefinder_linux.c b/src/modulefinder/sentry_modulefinder_linux.c index 595885b10c..37cf6ae80c 100644 --- a/src/modulefinder/sentry_modulefinder_linux.c +++ b/src/modulefinder/sentry_modulefinder_linux.c @@ -506,7 +506,7 @@ sentry__procmaps_module_to_value(const sentry_module_t *module) mmapped_module.is_mmapped = true; mmapped_module.num_mappings = 1; mmapped_module.mappings[0].addr - = (uint64_t)mm.ptr + module->offset_in_inode; + = (uint64_t)(uintptr_t)mm.ptr + module->offset_in_inode; mmapped_module.mappings[0].size = mm.len - module->offset_in_inode; sentry__procmaps_read_ids_from_elf(mod_val, &mmapped_module); diff --git a/src/sentry_cpu_relax.h b/src/sentry_cpu_relax.h index e19e6a22c8..de3312d4f4 100644 --- a/src/sentry_cpu_relax.h +++ b/src/sentry_cpu_relax.h @@ -13,8 +13,10 @@ #else # if defined(__i386__) || defined(__x86_64__) || defined(__amd64__) # define sentry__cpu_relax() __asm__ __volatile__("pause") -# elif defined(__aarch64__) || defined(__arm__) +# elif defined(__aarch64__) # define sentry__cpu_relax() __asm__ __volatile__("yield") +# elif defined(__arm__) +# define sentry__cpu_relax() __asm__ __volatile__("nop") # elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) # define sentry__cpu_relax() __asm__ __volatile__("or 27,27,27") # elif defined(__riscv) diff --git a/tests/unit/test_modulefinder.c b/tests/unit/test_modulefinder.c index 3173c3ba1d..27b36c6566 100644 --- a/tests/unit/test_modulefinder.c +++ b/tests/unit/test_modulefinder.c @@ -203,16 +203,17 @@ parse_elf_and_check_code_and_build_id(const char *rel_elf_path, sentry_module_t module = { 0 }; module.num_mappings = 1; - size_t *file_size = &module.mappings[0].size; - char **buf = (char **)&module.mappings[0].addr; sentry_value_t value = sentry_value_new_object(); sentry_path_t *elf_path = sentry__path_join_str(dir, rel_elf_path); - *buf = sentry__path_read_to_buffer(elf_path, file_size); + size_t file_size = 0; + char *buf = sentry__path_read_to_buffer(elf_path, &file_size); sentry__path_free(elf_path); + module.mappings[0].addr = (uint64_t)(uintptr_t)buf; + module.mappings[0].size = file_size; TEST_CHECK(sentry__procmaps_read_ids_from_elf(value, &module)); - sentry_free(*buf); + sentry_free(buf); sentry__path_free(dir); if (expected_code_id) { From b646b82bb27ca6a0a1cfac171e2755cb69ca8cef Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 4 Sep 2026 12:09:48 +0200 Subject: [PATCH 3/3] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84e433cb73..b11318dfa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - Native: clean up stale envelopes after crashes with `SENTRY_TRANSPORT=none`. ([#2049](https://github.com/getsentry/sentry-native/pull/2049)) - `sentry_set_trace` omits `parent_span_id` when the caller does not provide one, instead of serializing it as `null`. ([#2047](https://github.com/getsentry/sentry-native/pull/2047)) - Native/Linux i386: write valid thread stack descriptors to minidumps when stack addresses use the upper half of the 32-bit address space. ([#2054](https://github.com/getsentry/sentry-native/pull/2054)) +- Linux/ARM32: fix builds on 32-bit ARM systems, including 32-bit Raspberry Pi OS installations running a 64-bit kernel. ([#2063](https://github.com/getsentry/sentry-native/pull/2063)) **Thank you**: