Skip to content

Commit

Permalink
Implement segfault handler in Crystal
Browse files Browse the repository at this point in the history
Required adding some C bindings for various signal structures,
based on rust's fairly comprehensive libc bindings.

This removes the need to build and link a separate C library and
reduces the complexity of cross-compiling (at build-time), with
some added complexity when porting to a new platform.

`siginfo_t` can be fairly complex, involving large context-dependent
unions that vary across architecture and platform. In Crystal's
case, we only care about the segfault version of the structure,
so we omit the others.
  • Loading branch information
maxfierke committed Mar 2, 2021
1 parent b018f28 commit 074e63d
Show file tree
Hide file tree
Showing 22 changed files with 446 additions and 50 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,3 @@ all_spec
/src/llvm/ext/llvm_ext.o
/src/llvm/ext/llvm_ext.obj
/src/llvm/ext/llvm_ext.dwo
/src/ext/*.o
/src/ext/libcrystal.a
2 changes: 0 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ Additionally, all official documentation can be found on [the Crystal website](h
1. Fork it ( https://github.com/crystal-lang/crystal/fork )
2. Clone it

Be sure to execute `make libcrystal` inside the cloned repository.

Once in the cloned directory, and once you [installed Crystal](https://crystal-lang.org/install/),
you can execute `bin/crystal` instead of `crystal`. This is a wrapper that will use the cloned repository
as the standard library. Otherwise the barebones `crystal` executable uses the standard library that comes in
Expand Down
14 changes: 2 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,7 @@ SHELL = sh
LLVM_CONFIG := $(shell src/llvm/ext/find-llvm-config)
LLVM_EXT_DIR = src/llvm/ext
LLVM_EXT_OBJ = $(LLVM_EXT_DIR)/llvm_ext.o
LIB_CRYSTAL_SOURCES = $(shell find src/ext -name '*.c')
LIB_CRYSTAL_OBJS = $(subst .c,.o,$(LIB_CRYSTAL_SOURCES))
LIB_CRYSTAL_TARGET = src/ext/libcrystal.a
DEPS = $(LLVM_EXT_OBJ) $(LIB_CRYSTAL_TARGET)
CFLAGS += -fPIC $(if $(debug),-g -O0)
DEPS = $(LLVM_EXT_OBJ)
CXXFLAGS += $(if $(debug),-g -O0)
CRYSTAL_VERSION ?= $(shell cat src/VERSION)

Expand Down Expand Up @@ -99,11 +95,9 @@ docs: ## Generate standard library documentation
.PHONY: crystal
crystal: $(O)/crystal ## Build the compiler

.PHONY: deps llvm_ext libcrystal
.PHONY: deps llvm_ext
deps: $(DEPS) ## Build dependencies

llvm_ext: $(LLVM_EXT_OBJ)
libcrystal: $(LIB_CRYSTAL_TARGET)

$(O)/all_spec: $(DEPS) $(SOURCES) $(SPEC_SOURCES)
@mkdir -p $(O)
Expand All @@ -124,13 +118,9 @@ $(O)/crystal: $(DEPS) $(SOURCES)
$(LLVM_EXT_OBJ): $(LLVM_EXT_DIR)/llvm_ext.cc
$(CXX) -c $(CXXFLAGS) -o $@ $< $(shell $(LLVM_CONFIG) --cxxflags)

$(LIB_CRYSTAL_TARGET): $(LIB_CRYSTAL_OBJS)
$(AR) -rcs $@ $^

.PHONY: clean
clean: clean_crystal ## Clean up built directories and files
rm -rf $(LLVM_EXT_OBJ)
rm -rf $(LIB_CRYSTAL_OBJS) $(LIB_CRYSTAL_TARGET)

.PHONY: clean_crystal
clean_crystal: ## Clean up crystal built files
Expand Down
1 change: 0 additions & 1 deletion shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,5 @@ pkgs.stdenv.mkDerivation rec {

LLVM_CONFIG = "${llvm_suite.llvm}/bin/llvm-config";

# ld: warning: object file (.../src/ext/libcrystal.a(sigfault.o)) was built for newer OSX version (10.14) than being linked (10.12)
MACOSX_DEPLOYMENT_TARGET = "10.11";
}
4 changes: 0 additions & 4 deletions src/ext.cr

This file was deleted.

27 changes: 0 additions & 27 deletions src/ext/sigfault.c

This file was deleted.

2 changes: 1 addition & 1 deletion src/kernel.cr
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ end
end

Signal.setup_default_handlers
LibExt.setup_sigfault_handler
Signal.setup_sigfault_handler
{% end %}

{% if !flag?(:win32) %}
Expand Down
33 changes: 33 additions & 0 deletions src/lib_c/aarch64-darwin/c/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ lib LibC
SIGEMT = 7
SIGINFO = 29
SIGWINCH = 28
SIGSTKSZ = 131072

SIG_SETMASK = 3

Expand All @@ -42,9 +43,41 @@ lib LibC
SIG_DFL = SighandlerT.new(Pointer(Void).new(0_u64), Pointer(Void).null)
SIG_IGN = SighandlerT.new(Pointer(Void).new(1_u64), Pointer(Void).null)

SA_ONSTACK = 0x0001
SA_SIGINFO = 0x0040

struct SiginfoT
si_signo : Int
si_errno : Int
si_code : Int
si_pid : PidT
si_uid : UidT
si_status : Int
si_addr : Void*
_pad : StaticArray(SizeT, 9)
end

alias SigactionHandlerT = (Int, SiginfoT*, Void*) ->

struct Sigaction
# Technically a union, but only one can be valid and we only use sa_sigaction
# and not sa_handler (which would be a SighandlerT)
sa_sigaction : SigactionHandlerT
sa_mask : SigsetT
sa_flags : Int
end

struct StackT
ss_sp : Void*
ss_size : SizeT
ss_flags : Int
end

fun kill(x0 : PidT, x1 : Int) : Int
fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int
fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void
fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int
fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int
fun sigemptyset(SigsetT*) : Int
fun sigfillset(SigsetT*) : Int
fun sigaddset(SigsetT*, Int) : Int
Expand Down
30 changes: 30 additions & 0 deletions src/lib_c/aarch64-linux-gnu/c/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ lib LibC
SIGPWR = 30
SIGSTKFLT = 16
SIGUNUSED = 31
SIGSTKSZ = 16384

SIG_SETMASK = 2

Expand All @@ -46,9 +47,38 @@ lib LibC
val : ULong[32] # (1024 / (8 * sizeof(long)))
end

SA_ONSTACK = 0x08000000
SA_SIGINFO = 0x00000004

struct SiginfoT
si_signo : Int
si_errno : Int
si_code : Int
__pad0 : Int
si_addr : Void* # Assuming the sigfault form of siginfo_t
__pad1 : StaticArray(Int, 20) # __SI_PAD_SIZE (28) - sizeof(void*) (8) = 20
end

alias SigactionHandlerT = (Int, SiginfoT*, Void*) ->

struct Sigaction
sa_sigaction : SigactionHandlerT
sa_mask : SigsetT
sa_flags : Int
sa_restorer : Void*
end

struct StackT
ss_sp : Void*
ss_flags : Int
ss_size : SizeT
end

fun kill(pid : PidT, sig : Int) : Int
fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int
fun signal(sig : Int, handler : Int -> Void) : Int -> Void
fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int
fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int
fun sigemptyset(SigsetT*) : Int
fun sigfillset(SigsetT*) : Int
fun sigaddset(SigsetT*, Int) : Int
Expand Down
30 changes: 30 additions & 0 deletions src/lib_c/aarch64-linux-musl/c/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ lib LibC
SIGPWR = 30
SIGSTKFLT = 16
SIGUNUSED = LibC::SIGSYS
SIGSTKSZ = 12288

SIG_SETMASK = 2

Expand All @@ -45,9 +46,38 @@ lib LibC
val : ULong[16] # 128 / sizeof(long)
end

SA_ONSTACK = 0x08000000
SA_SIGINFO = 0x00000004

struct SiginfoT
si_signo : Int
si_errno : Int
si_code : Int
__pad0 : Int
si_addr : Void* # Assuming the sigfault form of siginfo_t
__pad1 : StaticArray(Int, 20) # __SI_PAD_SIZE (28) - sizeof(void*) (8) = 20
end

alias SigactionHandlerT = (Int, SiginfoT*, Void*) ->

struct Sigaction
sa_sigaction : SigactionHandlerT
sa_mask : SigsetT
sa_flags : Int
sa_restorer : Void*
end

struct StackT
ss_sp : Void*
ss_flags : Int
ss_size : SizeT
end

fun kill(x0 : PidT, x1 : Int) : Int
fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int
fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void
fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int
fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int
fun sigemptyset(SigsetT*) : Int
fun sigfillset(SigsetT*) : Int
fun sigaddset(SigsetT*, Int) : Int
Expand Down
29 changes: 29 additions & 0 deletions src/lib_c/arm-linux-gnueabihf/c/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ lib LibC
SIGPWR = 30
SIGSTKFLT = 16
SIGUNUSED = 31
SIGSTKSZ = 8192

SIG_SETMASK = 2

Expand All @@ -46,9 +47,37 @@ lib LibC
val : ULong[32] # (1024 / (8 * sizeof(long)))
end

SA_ONSTACK = 0x08000000
SA_SIGINFO = 0x00000004

struct SiginfoT
si_signo : Int
si_errno : Int
si_code : Int
si_addr : Void* # Assuming the sigfault form of siginfo_t
__pad : StaticArray(Int, 25) # __SI_PAD_SIZE (29) - sizeof(void*) (4) = 25
end

alias SigactionHandlerT = (Int, SiginfoT*, Void*) ->

struct Sigaction
sa_sigaction : SigactionHandlerT
sa_mask : SigsetT
sa_flags : Int
sa_restorer : Void*
end

struct StackT
ss_sp : Void*
ss_flags : Int
ss_size : SizeT
end

fun kill(pid : PidT, sig : Int) : Int
fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int
fun signal(sig : Int, handler : Int -> Void) : Int -> Void
fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int
fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int
fun sigemptyset(SigsetT*) : Int
fun sigfillset(SigsetT*) : Int
fun sigaddset(SigsetT*, Int) : Int
Expand Down
29 changes: 29 additions & 0 deletions src/lib_c/i386-linux-gnu/c/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ lib LibC
SIGPWR = 30
SIGSTKFLT = 16
SIGUNUSED = 31
SIGSTKSZ = 8192

SIG_SETMASK = 2

Expand All @@ -46,9 +47,37 @@ lib LibC
val : ULong[32] # (1024 / (8 * sizeof(long)))
end

SA_ONSTACK = 0x08000000
SA_SIGINFO = 0x00000004

struct SiginfoT
si_signo : Int
si_errno : Int
si_code : Int
si_addr : Void* # Assuming the sigfault form of siginfo_t
__pad : StaticArray(Int, 25) # __SI_PAD_SIZE (29) - sizeof(void*) (4) = 25
end

alias SigactionHandlerT = (Int, SiginfoT*, Void*) ->

struct Sigaction
sa_sigaction : SigactionHandlerT
sa_mask : SigsetT
sa_flags : Int
sa_restorer : Void*
end

struct StackT
ss_sp : Void*
ss_flags : Int
ss_size : SizeT
end

fun kill(pid : PidT, sig : Int) : Int
fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int
fun signal(sig : Int, handler : Int -> Void) : Int -> Void
fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int
fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int
fun sigemptyset(SigsetT*) : Int
fun sigfillset(SigsetT*) : Int
fun sigaddset(SigsetT*, Int) : Int
Expand Down
29 changes: 29 additions & 0 deletions src/lib_c/i386-linux-musl/c/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ lib LibC
SIGPWR = 30
SIGSTKFLT = 16
SIGUNUSED = LibC::SIGSYS
SIGSTKSZ = 8192

SIG_SETMASK = 2

Expand All @@ -45,9 +46,37 @@ lib LibC
bits : ULong[32] # 128 / sizeof(long)
end

SA_ONSTACK = 0x08000000
SA_SIGINFO = 0x00000004

struct SiginfoT
si_signo : Int
si_errno : Int
si_code : Int
si_addr : Void* # Assuming the sigfault form of siginfo_t
__pad : StaticArray(Int, 25) # __SI_PAD_SIZE (29) - sizeof(void*) (4) = 25
end

alias SigactionHandlerT = (Int, SiginfoT*, Void*) ->

struct Sigaction
sa_sigaction : SigactionHandlerT
sa_mask : SigsetT
sa_flags : Int
sa_restorer : Void*
end

struct StackT
ss_sp : Void*
ss_flags : Int
ss_size : SizeT
end

fun kill(x0 : PidT, x1 : Int) : Int
fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int
fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void
fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int
fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int
fun sigemptyset(SigsetT*) : Int
fun sigfillset(SigsetT*) : Int
fun sigaddset(SigsetT*, Int) : Int
Expand Down
Loading

0 comments on commit 074e63d

Please sign in to comment.