Skip to content

Commit

Permalink
fixed build for arm processors (#918)
Browse files Browse the repository at this point in the history
Fixed build on arm architecture.
Unification of the use of the own implementation of ucontext (based on libucontext) for the arm architecture. Previously, this implementation was used only for macOS, now also for linux.
  • Loading branch information
troy4eg authored Oct 23, 2023
1 parent c4031c7 commit efd53e4
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 257 deletions.
4 changes: 2 additions & 2 deletions common/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ prepend(COMMON_TL_METHODS_SOURCES ${COMMON_DIR}/tl/methods/
rwm.cpp
string.cpp)

if (APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
if (NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
prepend(COMMON_UCONTEXT_SOURCES ${COMMON_DIR}/ucontext/
ucontext.cpp)
ucontext-arm.cpp)
endif()

set(COMMON_ALL_SOURCES
Expand Down
57 changes: 7 additions & 50 deletions common/server/crash-dump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,51 +61,10 @@ static inline void crash_dump_write_reg(const char* reg_name, size_t reg_name_si
#define LITERAL_WITH_LENGTH(literal) literal, sizeof(literal) - 1

static inline void crash_dump_prepare_registers(crash_dump_buffer_t *buffer, void *ucontext) {
#if defined(__APPLE__)
#ifdef __arm64__ // Apple M1
#ifdef __x86_64__
#ifdef __APPLE__
const auto *uc = static_cast<ucontext_t *>(ucontext);

crash_dump_write_reg(LITERAL_WITH_LENGTH("SP=0x"), uc->uc_mcontext->__ss.__sp, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("PC=0x"), uc->uc_mcontext->__ss.__pc, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("LR=0x"), uc->uc_mcontext->__ss.__lr, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("FP=0x"), uc->uc_mcontext->__ss.__fp, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("PSTATE=0x"), uc->uc_mcontext->__ss.__cpsr, buffer);

crash_dump_write_reg(LITERAL_WITH_LENGTH("X0=0x"), uc->uc_mcontext->__ss.__x[0], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X1=0x"), uc->uc_mcontext->__ss.__x[1], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X2=0x"), uc->uc_mcontext->__ss.__x[2], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X3=0x"), uc->uc_mcontext->__ss.__x[3], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X4=0x"), uc->uc_mcontext->__ss.__x[4], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X5=0x"), uc->uc_mcontext->__ss.__x[5], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X6=0x"), uc->uc_mcontext->__ss.__x[6], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X7=0x"), uc->uc_mcontext->__ss.__x[7], buffer);

crash_dump_write_reg(LITERAL_WITH_LENGTH("X8=0x"), uc->uc_mcontext->__ss.__x[8], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X9=0x"), uc->uc_mcontext->__ss.__x[9], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X10=0x"), uc->uc_mcontext->__ss.__x[10], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X11=0x"), uc->uc_mcontext->__ss.__x[11], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X12=0x"), uc->uc_mcontext->__ss.__x[12], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X13=0x"), uc->uc_mcontext->__ss.__x[13], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X14=0x"), uc->uc_mcontext->__ss.__x[14], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X15=0x"), uc->uc_mcontext->__ss.__x[15], buffer);

crash_dump_write_reg(LITERAL_WITH_LENGTH("X16=0x"), uc->uc_mcontext->__ss.__x[16], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X17=0x"), uc->uc_mcontext->__ss.__x[17], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X18=0x"), uc->uc_mcontext->__ss.__x[18], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X19=0x"), uc->uc_mcontext->__ss.__x[19], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X20=0x"), uc->uc_mcontext->__ss.__x[20], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X21=0x"), uc->uc_mcontext->__ss.__x[21], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X22=0x"), uc->uc_mcontext->__ss.__x[22], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X23=0x"), uc->uc_mcontext->__ss.__x[23], buffer);

crash_dump_write_reg(LITERAL_WITH_LENGTH("X24=0x"), uc->uc_mcontext->__ss.__x[24], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X25=0x"), uc->uc_mcontext->__ss.__x[25], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X26=0x"), uc->uc_mcontext->__ss.__x[26], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X27=0x"), uc->uc_mcontext->__ss.__x[27], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X28=0x"), uc->uc_mcontext->__ss.__x[28], buffer);
#else
const auto *uc = static_cast<ucontext_t *>(ucontext);

crash_dump_write_reg(LITERAL_WITH_LENGTH("RIP=0x"), uc->uc_mcontext->__ss.__rip, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("RSP=0x"), uc->uc_mcontext->__ss.__rsp, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("RBP=0x"), uc->uc_mcontext->__ss.__rbp, buffer);
Expand All @@ -126,8 +85,7 @@ static inline void crash_dump_prepare_registers(crash_dump_buffer_t *buffer, voi
crash_dump_write_reg(LITERAL_WITH_LENGTH("R13=0x"), uc->uc_mcontext->__ss.__r13, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("R14=0x"), uc->uc_mcontext->__ss.__r14, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("R15=0x"), uc->uc_mcontext->__ss.__r15, buffer);
#endif
#elif defined(__x86_64__)
#else
const auto *uc = static_cast<ucontext_t *>(ucontext);

crash_dump_write_reg(LITERAL_WITH_LENGTH("RIP=0x"), uc->uc_mcontext.gregs[REG_RIP], buffer);
Expand All @@ -152,12 +110,14 @@ static inline void crash_dump_prepare_registers(crash_dump_buffer_t *buffer, voi
crash_dump_write_reg(LITERAL_WITH_LENGTH("R13=0x"), uc->uc_mcontext.gregs[REG_R13], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("R14=0x"), uc->uc_mcontext.gregs[REG_R14], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("R15=0x"), uc->uc_mcontext.gregs[REG_R15], buffer);
#elif defined(__aarch64__) || defined(__arm64__)
#endif
#elif defined(__arm64__) || defined (__aarch64__)
const auto *uc = static_cast<ucontext_t_portable *>(ucontext);

crash_dump_write_reg(LITERAL_WITH_LENGTH("SP=0x"), uc->uc_mcontext.sp, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("PC=0x"), uc->uc_mcontext.pc, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("FP=0x"), uc->uc_mcontext.fp, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("LR=0x"), uc->uc_mcontext.lr, buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("PSTATE=0x"), uc->uc_mcontext.pstate, buffer);

crash_dump_write_reg(LITERAL_WITH_LENGTH("X0=0x"), uc->uc_mcontext.regs[0], buffer);
Expand Down Expand Up @@ -192,9 +152,6 @@ static inline void crash_dump_prepare_registers(crash_dump_buffer_t *buffer, voi
crash_dump_write_reg(LITERAL_WITH_LENGTH("X26=0x"), uc->uc_mcontext.regs[26], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X27=0x"), uc->uc_mcontext.regs[27], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X28=0x"), uc->uc_mcontext.regs[28], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X29=0x"), uc->uc_mcontext.regs[29], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("X30=0x"), uc->uc_mcontext.regs[30], buffer);

#else
#error "Unsupported arch"
#endif
Expand Down
181 changes: 181 additions & 0 deletions common/ucontext/ucontext-arm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// Compiler for PHP (aka KPHP)
// libucontext (c) https://github.com/kaniini/libucontext/tree/master (copied as third-party and slightly modified)
// Copyright (c) 2023 LLC «V Kontakte»
// Distributed under the GPL v3 License, see LICENSE.notice.txt

#include "common/ucontext/ucontext-arm.h"

#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>

enum { SP_OFFSET = 432, PC_OFFSET = 440, PSTATE_OFFSET = 448, FPSIMD_CONTEXT_OFFSET = 464 };

#define STR(x) #x
#ifdef __APPLE__
#define NAME(x) STR(_##x)
#else
#define NAME(x) #x
#endif

#define R0_OFFSET REG_OFFSET(0)

#define REG_OFFSET(__reg) (MCONTEXT_GREGS + ((__reg)*REG_SZ))

#define REG_SZ (8)
#define MCONTEXT_GREGS (184)

static_assert(offsetof(libucontext_ucontext, uc_mcontext.regs[0]) == R0_OFFSET, "R0_OFFSET is invalid");
static_assert(offsetof(libucontext_ucontext, uc_mcontext.sp) == SP_OFFSET, "SP_OFFSET is invalid");
static_assert(offsetof(libucontext_ucontext, uc_mcontext.pc) == PC_OFFSET, "PC_OFFSET is invalid");
static_assert(offsetof(libucontext_ucontext, uc_mcontext.pstate) == PSTATE_OFFSET, "PSTATE_OFFSET is invalid");

__attribute__((visibility("hidden"))) void libucontext_trampoline() {
libucontext_ucontext *uc_link = nullptr;

asm("mov %0, x19" : "=r"((uc_link)));

if (uc_link == nullptr) {
exit(0);
}

libucontext_setcontext(uc_link);
}

void libucontext_makecontext(libucontext_ucontext *ucp, void (*func)(), int argc, ...) {
unsigned long *sp;
unsigned long *regp;
va_list va;
int i;

sp = reinterpret_cast<unsigned long *>(reinterpret_cast<uintptr_t>(ucp->uc_stack.ss_sp) + ucp->uc_stack.ss_size);
sp -= argc < 8 ? 0 : argc - 8;
sp = reinterpret_cast<unsigned long *>(((reinterpret_cast<uintptr_t>(sp) & -16L)));

ucp->uc_mcontext.sp = reinterpret_cast<uintptr_t>(sp);
ucp->uc_mcontext.pc = reinterpret_cast<uintptr_t>(func);
ucp->uc_mcontext.regs[19] = reinterpret_cast<uintptr_t>(ucp->uc_link);
ucp->uc_mcontext.lr = reinterpret_cast<uintptr_t>(&libucontext_trampoline);

va_start(va, argc);

regp = &(ucp->uc_mcontext.regs[0]);

for (i = 0; (i < argc && i < 8); i++) {
*regp++ = va_arg(va, unsigned long);
}

for (; i < argc; i++) {
*sp++ = va_arg(va, unsigned long);
}

va_end(va);
}

asm(".global " NAME(libucontext_getcontext) ";\n"
".align 2;\n"
NAME(libucontext_getcontext) ":\n"
"str xzr, [x0, #((184) + ((0) * (8)))]\n" // #REG_OFFSET(0)
/* save GPRs */
"stp x0, x1, [x0, #((184) + ((0) * (8)))]\n" // REG_OFFSET(0)
"stp x2, x3, [x0, #((184) + ((2) * (8)))]\n" // REG_OFFSET(2)
"stp x4, x5, [x0, #((184) + ((4) * (8)))]\n" // REG_OFFSET(4)
"stp x6, x7, [x0, #((184) + ((6) * (8)))]\n" // REG_OFFSET(6)
"stp x8, x9, [x0, #((184) + ((8) * (8)))]\n" // REG_OFFSET(8)
"stp x10, x11, [x0, #((184) + ((10) * (8)))]\n" // REG_OFFSET(10)
"stp x12, x13, [x0, #((184) + ((12) * (8)))]\n" // REG_OFFSET(12)
"stp x14, x15, [x0, #((184) + ((14) * (8)))]\n" // REG_OFFSET(14)
"stp x16, x17, [x0, #((184) + ((16) * (8)))]\n" // REG_OFFSET(16)
"stp x18, x19, [x0, #((184) + ((18) * (8)))]\n" // REG_OFFSET(18)
"stp x20, x21, [x0, #((184) + ((20) * (8)))]\n" // REG_OFFSET(20)
"stp x22, x23, [x0, #((184) + ((22) * (8)))]\n" // REG_OFFSET(22)
"stp x24, x25, [x0, #((184) + ((24) * (8)))]\n" // REG_OFFSET(24)
"stp x26, x27, [x0, #((184) + ((26) * (8)))]\n" // REG_OFFSET(26)
"stp x28, x29, [x0, #((184) + ((28) * (8)))]\n" // REG_OFFSET(28)
"str x30, [x0, #((184) + ((30) * (8)))]\n" // REG_OFFSET(30)
/* save current program counter in link register */
"str x30, [x0, #440]\n" // PC_OFFSET
/* save current stack pointer */
"mov x2, sp\n"
"str x2, [x0, #432]\n" // SP_OFFSET
/* save pstate */
"str xzr, [x0, #448]\n" // PSTATE_OFFSET
"add x2, x0, #464\n" // FPSIMD_CONTEXT_OFFSET
"stp q8, q9, [x2, #144]\n"
"stp q10, q11, [x2, #176]\n"
"stp q12, q13, [x2, #208]\n"
"stp q14, q15, [x2, #240]\n"
"mov x0, #0\n"
"ret\n");
asm(".global " NAME(libucontext_setcontext) ";\n"
".align 2;\n"
NAME(libucontext_setcontext) ":\n"
/* restore GPRs */
"ldp x18, x19, [x0, #((184) + ((18) * (8)))]\n" // REG_OFFSET(18)
"ldp x20, x21, [x0, #((184) + ((20) * (8)))]\n" // REG_OFFSET(20)
"ldp x22, x23, [x0, #((184) + ((22) * (8)))]\n" // REG_OFFSET(22)
"ldp x24, x25, [x0, #((184) + ((24) * (8)))]\n" // REG_OFFSET(24)
"ldp x26, x27, [x0, #((184) + ((26) * (8)))]\n" // REG_OFFSET(26)
"ldp x28, x29, [x0, #((184) + ((28) * (8)))]\n" // REG_OFFSET(28)
"ldr x30, [x0, #((184) + ((30) * (8)))]\n" // REG_OFFSET(30)
/* save current stack pointer */
"ldr x2, [x0, #432]\n" // SP_OFFSET
"mov sp, x2\n"
"add x2, x0, #464\n" // FPSIMD_CONTEXT_OFFSET
"ldp q8, q9, [x2, #144]\n"
"ldp q10, q11, [x2, #176]\n"
"ldp q12, q13, [x2, #208]\n"
"ldp q14, q15, [x2, #240]\n"
/* save current program counter in link register */
"ldr x16, [x0, #440]\n" // PC_OFFSET
/* restore args */
"ldp x2, x3, [x0, #((184) + ((2) * (8)))]\n" // REG_OFFSET(2)
"ldp x4, x5, [x0, #((184) + ((4) * (8)))]\n" // REG_OFFSET(4)
"ldp x6, x7, [x0, #((184) + ((6) * (8)))]\n" // REG_OFFSET(6)
"ldp x0, x1, [x0, #((184) + ((0) * (8)))]\n" // REG_OFFSET(8)
/* jump to new PC */
"br x16\n");
asm(".global " NAME(libucontext_swapcontext) ";\n"
".align 2;\n"
NAME(libucontext_swapcontext) ":\n"
"str xzr, [x0, #((184) + ((0) * (8)))]\n" // REG_OFFSET(0)
/* save GPRs */
"stp x2, x3, [x0, #((184) + ((2) * (8)))]\n" // REG_OFFSET(2)
"stp x4, x5, [x0, #((184) + ((4) * (8)))]\n" // REG_OFFSET(4)
"stp x6, x7, [x0, #((184) + ((6) * (8)))]\n" // REG_OFFSET(6)
"stp x8, x9, [x0, #((184) + ((8) * (8)))]\n" // REG_OFFSET(8)
"stp x10, x11, [x0, #((184) + ((10) * (8)))]\n" // REG_OFFSET(10)
"stp x12, x13, [x0, #((184) + ((12) * (8)))]\n" // REG_OFFSET(12)
"stp x14, x15, [x0, #((184) + ((14) * (8)))]\n" // REG_OFFSET(14)
"stp x16, x17, [x0, #((184) + ((16) * (8)))]\n" // REG_OFFSET(16)
"stp x18, x19, [x0, #((184) + ((18) * (8)))]\n" // REG_OFFSET(18)
"stp x20, x21, [x0, #((184) + ((20) * (8)))]\n" // REG_OFFSET(20)
"stp x22, x23, [x0, #((184) + ((22) * (8)))]\n" // REG_OFFSET(22)
"stp x24, x25, [x0, #((184) + ((24) * (8)))]\n" // REG_OFFSET(24)
"stp x26, x27, [x0, #((184) + ((26) * (8)))]\n" // REG_OFFSET(26)
"stp x28, x29, [x0, #((184) + ((28) * (8)))]\n" // REG_OFFSET(28)
"str x30, [x0, #((184) + ((30) * (8)))]\n" // REG_OFFSET(30)
/* save current program counter in link register */
"str x30, [x0, #440]\n" // PC_OFFSET
/* save current stack pointer */
"mov x2, sp\n"
"str x2, [x0, #432]\n" // SP_OFFSET
/* save pstate */
"str xzr, [x0, #448]\n" // PSTATE_OFFSET
"add x2, x0, #464\n" // FPSIMD_CONTEXT_OFFSET
"stp q8, q9, [x2, #144]\n"
"stp q10, q11, [x2, #176]\n"
"stp q12, q13, [x2, #208]\n"
"stp q14, q15, [x2, #240]\n"
/* context to swap to is in x1 so... we move to x0 and call setcontext */
/* store our link register in x28 */
"mov x28, x30\n"
/* move x1 to x0 and call setcontext */
"mov x0, x1\n"
"bl " NAME(libucontext_setcontext) "\n"
/* hmm, we came back here try to return */
"mov x30, x28\n"
"ret\n");
4 changes: 2 additions & 2 deletions common/ucontext/ucontext.h → common/ucontext/ucontext-arm.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

struct libucontext_mcontext {
unsigned long fault_address;
unsigned long regs[31];
unsigned long sp, pc, pstate;
unsigned long regs[29];
unsigned long fp, lr, sp, pc, pstate;
long double __reserved[256];
};

Expand Down
4 changes: 2 additions & 2 deletions common/ucontext/ucontext-portable.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#pragma once

#if !(defined(__APPLE__) && defined(__arm64__))
#ifdef __x86_64__
// for x86 mac or x86/arm linux, we just use makecontext(), ucontext_t and other native functions
#include <ucontext.h>

Expand All @@ -16,7 +16,7 @@

#else
// for M1, we can't use native makecontext() and others: they compile, but hang up when called
#include "common/ucontext/ucontext.h"
#include "common/ucontext/ucontext-arm.h"

#define ucontext_t_portable libucontext_ucontext
#define setcontext_portable libucontext_setcontext
Expand Down
Loading

0 comments on commit efd53e4

Please sign in to comment.