Skip to content

Commit 34c081d

Browse files
authored
Merge branch 'master' into feat/native-backend-xbox
2 parents 3b17b3b + eff0861 commit 34c081d

21 files changed

Lines changed: 222 additions & 49 deletions

.github/workflows/ci.yml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ jobs:
6969
CC: gcc-9
7070
CXX: g++-9
7171
TEST_X86: 1
72+
- name: Linux Arm32 (gcc-arm-linux-gnueabihf + qemu-user)
73+
os: ubuntu-24.04-arm
74+
CC: arm-linux-gnueabihf-gcc
75+
CXX: arm-linux-gnueabihf-g++
76+
TEST_ARM32: 1
77+
TEST_QEMU: 1
7278
- name: Linux (GCC 9.5.0)
7379
os: ubuntu-24.04
7480
CC: gcc-9
@@ -223,6 +229,8 @@ jobs:
223229
CXX: ${{ matrix.CXX }}
224230
TEST_X86: ${{ matrix.TEST_X86 }}
225231
TEST_MINGW: ${{ matrix.TEST_MINGW }}
232+
TEST_ARM32: ${{ matrix.TEST_ARM32 }}
233+
TEST_QEMU: ${{ matrix.TEST_QEMU }}
226234
USE_SCCACHE: ${{ matrix.USE_SCCACHE }}
227235
SCCACHE_GHA_ENABLED: ${{ matrix.USE_SCCACHE && 'true' || '' }}
228236
ERROR_ON_WARNINGS: ${{ matrix.ERROR_ON_WARNINGS }}
@@ -258,7 +266,7 @@ jobs:
258266
[ -n "$CC" ] && [ -n "$CXX" ] || { echo "Ubuntu runner configurations require toolchain selection via CC and CXX" >&2; exit 1; }
259267
260268
- name: Installing Linux Dependencies
261-
if: ${{ runner.os == 'Linux' && !env['TEST_X86'] && !env['ANDROID_API'] && !matrix.container }}
269+
if: ${{ runner.os == 'Linux' && !env['TEST_X86'] && !env['TEST_ARM32'] && !env['ANDROID_API'] && !matrix.container }}
262270
run: |
263271
sudo apt update
264272
# Install common dependencies
@@ -295,6 +303,26 @@ jobs:
295303
sudo apt update
296304
sudo apt install cmake "${CC}-multilib" "${CXX}-multilib" zlib1g-dev:i386 libssl-dev:i386 libcurl4-openssl-dev:i386 liblzma-dev:i386
297305
306+
- name: Installing Linux arm32 Dependencies
307+
if: ${{ runner.os == 'Linux' && env['TEST_ARM32'] && !matrix.container }}
308+
run: |
309+
sudo dpkg --add-architecture armhf
310+
sudo apt update
311+
sudo apt install -y \
312+
cmake \
313+
gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf \
314+
zlib1g-dev:armhf \
315+
libssl-dev:armhf \
316+
libcurl4-openssl-dev:armhf \
317+
liblzma-dev:armhf \
318+
libstdc++6:armhf
319+
320+
- name: Installing qemu-user
321+
if: ${{ runner.os == 'Linux' && env['TEST_QEMU'] && !matrix.container }}
322+
run: |
323+
sudo apt update
324+
sudo apt install -y qemu-user-static binfmt-support
325+
298326
- name: Installing Alpine Linux Dependencies
299327
if: ${{ contains(matrix.container, 'alpine') }}
300328
run: |

.github/workflows/codeql.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
submodules: 'recursive'
3131

3232
- name: Initialize CodeQL
33-
uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # pin@v4.35.1
33+
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # pin@v4.35.2
3434
with:
3535
languages: ${{ matrix.language }}
3636

@@ -64,4 +64,4 @@ jobs:
6464
cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo && cmake --build build --parallel
6565
6666
- name: Perform CodeQL Analysis
67-
uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # pin@v4.35.1
67+
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # pin@v4.35.2

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55
**Features**:
66

77
- Enable experimental `native` backend on Xbox ([#1666](https://github.com/getsentry/sentry-native/pull/1666))
8+
- Linux: support 32-bit ARM. ([#1659](https://github.com/getsentry/sentry-native/issues/1659))
89

910
**Fixes**:
1011

1112
- Linux: handle `ENOSYS` in `read_safely` to fix empty module list in seccomp-restricted environments. ([#1655](https://github.com/getsentry/sentry-native/pull/1655))
1213
- macOS: avoid stdio deadlock in breakpad exception handler. ([#1656](https://github.com/getsentry/sentry-native/pull/1656))
14+
- Crashpad: build for 32-bit ARM on Linux. ([#1659](https://github.com/getsentry/sentry-native/issues/1659))
15+
- Native: build for 32-bit ARM on Linux. ([#1659](https://github.com/getsentry/sentry-native/issues/1659))
16+
- Inproc: build vendored libunwind for 32-bit ARM on Linux. ([#1659](https://github.com/getsentry/sentry-native/issues/1659))
1317

1418
## 0.13.7
1519

src/backends/native/minidump/sentry_minidump_format.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,13 @@ PACKED_STRUCT_BEGIN
304304
typedef struct {
305305
uint32_t context_flags;
306306
uint32_t r[13]; // R0-R12
307-
uint32_t sp;
308-
uint32_t lr;
309-
uint32_t pc;
307+
uint32_t sp; // R13
308+
uint32_t lr; // R14
309+
uint32_t pc; // R15
310310
uint32_t cpsr;
311+
uint64_t fpscr;
312+
uint64_t fpregs[32]; // D0-D31
313+
uint32_t fpextra[8];
311314
} PACKED_ATTR minidump_context_arm_t;
312315
PACKED_STRUCT_END
313316
#endif

src/backends/native/minidump/sentry_minidump_linux.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,34 @@ ptrace_get_thread_registers(pid_t tid, ucontext_t *uctx)
273273
SENTRY_DEBUGF("ptrace(PTRACE_GETREGS) failed for thread %d: %s", tid,
274274
strerror(errno));
275275
}
276+
# elif defined(__arm__)
277+
struct user_regs regs;
278+
if (ptrace(PTRACE_GETREGS, tid, NULL, &regs) == 0) {
279+
// uregs[0..15] = R0..R15, uregs[16] = CPSR
280+
uctx->uc_mcontext.arm_r0 = regs.uregs[0];
281+
uctx->uc_mcontext.arm_r1 = regs.uregs[1];
282+
uctx->uc_mcontext.arm_r2 = regs.uregs[2];
283+
uctx->uc_mcontext.arm_r3 = regs.uregs[3];
284+
uctx->uc_mcontext.arm_r4 = regs.uregs[4];
285+
uctx->uc_mcontext.arm_r5 = regs.uregs[5];
286+
uctx->uc_mcontext.arm_r6 = regs.uregs[6];
287+
uctx->uc_mcontext.arm_r7 = regs.uregs[7];
288+
uctx->uc_mcontext.arm_r8 = regs.uregs[8];
289+
uctx->uc_mcontext.arm_r9 = regs.uregs[9];
290+
uctx->uc_mcontext.arm_r10 = regs.uregs[10];
291+
uctx->uc_mcontext.arm_fp = regs.uregs[11];
292+
uctx->uc_mcontext.arm_ip = regs.uregs[12];
293+
uctx->uc_mcontext.arm_sp = regs.uregs[13];
294+
uctx->uc_mcontext.arm_lr = regs.uregs[14];
295+
uctx->uc_mcontext.arm_pc = regs.uregs[15];
296+
uctx->uc_mcontext.arm_cpsr = regs.uregs[16];
297+
success = true;
298+
SENTRY_DEBUGF("Thread %d: captured registers via ptrace, SP=0x%lx", tid,
299+
(unsigned long)regs.uregs[13]);
300+
} else {
301+
SENTRY_DEBUGF("ptrace(PTRACE_GETREGS) failed for thread %d: %s", tid,
302+
strerror(errno));
303+
}
276304
# endif
277305

278306
// Detach from thread
@@ -749,6 +777,35 @@ write_thread_context(
749777

750778
return write_data(writer, &context, sizeof(context));
751779

780+
# elif defined(__arm__)
781+
(void)tid; // Unused on ARM32 - no VFP capture implemented yet
782+
783+
minidump_context_arm_t context = { 0 };
784+
// MD_CONTEXT_ARM | CONTROL | INTEGER — breakpad-style 0x40000000 base
785+
// (not Microsoft's 0x00200000; rust-minidump keys off the breakpad value)
786+
context.context_flags = 0x40000003;
787+
788+
// Copy general purpose registers R0-R10 from Linux ucontext
789+
context.r[0] = uctx->uc_mcontext.arm_r0;
790+
context.r[1] = uctx->uc_mcontext.arm_r1;
791+
context.r[2] = uctx->uc_mcontext.arm_r2;
792+
context.r[3] = uctx->uc_mcontext.arm_r3;
793+
context.r[4] = uctx->uc_mcontext.arm_r4;
794+
context.r[5] = uctx->uc_mcontext.arm_r5;
795+
context.r[6] = uctx->uc_mcontext.arm_r6;
796+
context.r[7] = uctx->uc_mcontext.arm_r7;
797+
context.r[8] = uctx->uc_mcontext.arm_r8;
798+
context.r[9] = uctx->uc_mcontext.arm_r9;
799+
context.r[10] = uctx->uc_mcontext.arm_r10;
800+
context.r[11] = uctx->uc_mcontext.arm_fp; // R11 (FP)
801+
context.r[12] = uctx->uc_mcontext.arm_ip; // R12 (IP)
802+
context.sp = uctx->uc_mcontext.arm_sp;
803+
context.lr = uctx->uc_mcontext.arm_lr;
804+
context.pc = uctx->uc_mcontext.arm_pc;
805+
context.cpsr = uctx->uc_mcontext.arm_cpsr;
806+
807+
return write_data(writer, &context, sizeof(context));
808+
752809
# else
753810
# error "Unsupported architecture for Linux"
754811
# endif
@@ -1285,6 +1342,8 @@ ptrace_capture_thread(
12851342
ptrace_sp = ptrace_ctx.uc_mcontext.sp;
12861343
# elif defined(__i386__)
12871344
ptrace_sp = ptrace_ctx.uc_mcontext.gregs[REG_ESP];
1345+
# elif defined(__arm__)
1346+
ptrace_sp = ptrace_ctx.uc_mcontext.arm_sp;
12881347
# endif
12891348

12901349
if (ptrace_sp != 0) {
@@ -1369,6 +1428,8 @@ write_thread_list_stream(minidump_writer_t *writer, minidump_directory_t *dir)
13691428
sp = uctx->uc_mcontext.sp;
13701429
# elif defined(__i386__)
13711430
sp = uctx->uc_mcontext.gregs[REG_ESP];
1431+
# elif defined(__arm__)
1432+
sp = uctx->uc_mcontext.arm_sp;
13721433
# endif
13731434

13741435
SENTRY_DEBUGF("Thread %u: has context, SP=0x%llx",

tests/build_config.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ def get_platform_cmake_args():
5151
args.append("-AWin32")
5252
elif sys.platform == "linux" and os.environ.get("TEST_X86"):
5353
args.append("-DSENTRY_BUILD_FORCE32=ON")
54+
elif sys.platform == "linux" and os.environ.get("TEST_ARM32"):
55+
args.extend(
56+
[
57+
"-DCMAKE_SYSTEM_NAME=Linux",
58+
"-DCMAKE_SYSTEM_PROCESSOR=arm",
59+
"-DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc",
60+
"-DCMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++",
61+
"-DCMAKE_ASM_COMPILER=arm-linux-gnueabihf-gcc",
62+
]
63+
)
5464

5565
if "asan" in os.environ.get("RUN_ANALYZER", ""):
5666
args.append("-DWITH_ASAN_OPTION=ON")

tests/conditions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
is_aix = sys.platform == "aix" or sys.platform == "os400"
66
is_android = os.environ.get("ANDROID_API")
77
is_x86 = os.environ.get("TEST_X86")
8+
is_arm32 = bool(os.environ.get("TEST_ARM32"))
9+
is_qemu = bool(os.environ.get("TEST_QEMU"))
810
is_asan = "asan" in os.environ.get("RUN_ANALYZER", "")
911
is_tsan = "tsan" in os.environ.get("RUN_ANALYZER", "")
1012
is_kcov = "kcov" in os.environ.get("RUN_ANALYZER", "")

tests/test_build_static.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import sys
33
import os
44
import pytest
5-
from .conditions import has_breakpad, has_crashpad, has_native, is_android
5+
from .conditions import has_breakpad, has_crashpad, has_native, is_android, is_qemu
66

77

88
def test_static_lib(cmake):
@@ -16,7 +16,7 @@ def test_static_lib(cmake):
1616
)
1717

1818
# on linux we can use `ldd` to check that we don’t link to `libsentry.so`
19-
if sys.platform == "linux" and not is_android:
19+
if sys.platform == "linux" and not is_android and not is_qemu:
2020
output = subprocess.check_output("ldd sentry_example", cwd=tmp_path, shell=True)
2121
assert b"libsentry.so" not in output
2222

@@ -40,9 +40,8 @@ def test_static_lib(cmake):
4040
output = subprocess.check_output(
4141
"file sentry_example", cwd=tmp_path, shell=True
4242
)
43-
assert (
44-
b"ELF 32-bit" if os.environ.get("TEST_X86") else b"ELF 64-bit"
45-
) in output
43+
is_32bit = os.environ.get("TEST_X86") or os.environ.get("TEST_ARM32")
44+
assert (b"ELF 32-bit" if is_32bit else b"ELF 64-bit") in output
4645

4746

4847
@pytest.mark.skipif(not has_crashpad, reason="test needs crashpad backend")

tests/test_dotnet_signals.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import pytest
99

1010
from tests import adb
11-
from tests.conditions import is_android, is_tsan, is_x86, is_asan
11+
from tests.conditions import is_android, is_arm32, is_tsan, is_x86, is_asan
1212

1313
project_fixture_path = pathlib.Path("tests/fixtures/dotnet_signal")
1414

@@ -67,7 +67,14 @@ def run_dotnet_native_crash(tmp_path):
6767

6868

6969
@pytest.mark.skipif(
70-
bool(sys.platform != "linux" or is_x86 or is_asan or is_tsan or is_android),
70+
bool(
71+
sys.platform != "linux"
72+
or is_x86
73+
or is_arm32
74+
or is_asan
75+
or is_tsan
76+
or is_android
77+
),
7178
reason="dotnet signal handling is currently only supported on 64-bit Linux without sanitizers",
7279
)
7380
def test_dotnet_signals_inproc(cmake):
@@ -171,7 +178,14 @@ def run_aot_native_crash(tmp_path):
171178

172179

173180
@pytest.mark.skipif(
174-
bool(sys.platform != "linux" or is_x86 or is_asan or is_tsan or is_android),
181+
bool(
182+
sys.platform != "linux"
183+
or is_x86
184+
or is_arm32
185+
or is_asan
186+
or is_tsan
187+
or is_android
188+
),
175189
reason="dotnet AOT signal handling is currently only supported on 64-bit Linux without sanitizers",
176190
)
177191
def test_aot_signals_inproc(cmake):

0 commit comments

Comments
 (0)