diff --git a/INSTALL.md b/INSTALL.md index 5f3d2774f8..6c4d4e8d1d 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -52,6 +52,20 @@ This will take a few minutes. After installing `automake`, `autoconf-archive`, `pkg-config`, and `libtool`, you're ready to build Vere. +#### Debugger + +macOS is curious operating system because the kernel is derived from from two codebases, the Mach kernel and the BSD kernel. It inherits two different hardware exception handling facilities, Mach exceptions and POSIX signals. We use `libsigsegv` and utilize the POSIX signals which is usually fine except when it comes to debugging with `lldb`. + +`lldb` hijacks the Mach exception ports for the task when it attaches to the process. Mach exceptions get handled before POSIX signals which means that as soon as vere faults (this happens often) `lldb` stop with a `EXC_BAD_ACCESS`. It is impossible to continue debugging from this state without the workaround we implemented in https://github.com/urbit/vere/pull/611. + +There are more annoying warts with `lldb` currently. First, if you attach the debugger when booting the ship with `lldb -- your-ship/.run` you have to specify `-t`, otherwise the ship is unable to boot for mysterious reasons. The other option is to start the ship and attach afterwards with `lldb -p PID`. Afterwards you should do this dance: + +``` +p (void)darwin_register_mach_exception_handler() +pro hand -p true -s false -n false SIGBUS +pro hand -p true -s false -n false SIGSEGV +``` + ## Build Commands Once you install the prerequisites, you're ready to build: diff --git a/bazel/common_settings.bzl b/bazel/common_settings.bzl index 6a61de1292..68a2232cd1 100644 --- a/bazel/common_settings.bzl +++ b/bazel/common_settings.bzl @@ -14,7 +14,7 @@ string_flag = rule( def vere_library(copts = [], linkopts = [], **kwargs): native.cc_library( copts = copts + select({ - "//:debug": ["-O0", "-g3", "-DC3DBG"], + "//:debug": ["-O0", "-g3", "-DC3DBG", "-fdebug-compilation-dir=."], "//conditions:default": ["-O3"] }) + select({ "//:lto": ['-flto'], @@ -39,7 +39,7 @@ def vere_library(copts = [], linkopts = [], **kwargs): def vere_binary(copts = [], linkopts = [], **kwargs): native.cc_binary( copts = copts + select({ - "//:debug": ["-O0", "-g3", "-DC3DBG"], + "//:debug": ["-O0", "-g3", "-DC3DBG", "-fdebug-compilation-dir=."], "//conditions:default": ["-O3"] }) + select({ "//:lto": ['-flto'], diff --git a/pkg/vere/BUILD.bazel b/pkg/vere/BUILD.bazel index 91a933517a..e736d0e8e1 100644 --- a/pkg/vere/BUILD.bazel +++ b/pkg/vere/BUILD.bazel @@ -110,6 +110,7 @@ vere_library( "@platforms//os:macos": [ "platform/darwin/daemon.c", "platform/darwin/ptty.c", + "platform/darwin/mach.c", ], "@platforms//os:linux": [ "platform/linux/daemon.c", diff --git a/pkg/vere/main.c b/pkg/vere/main.c index b97c39ab50..2222f87dd1 100644 --- a/pkg/vere/main.c +++ b/pkg/vere/main.c @@ -1140,7 +1140,6 @@ _cw_serf_commence(c3_i argc, c3_c* argv[]) fprintf(stderr, "serf: missing args\n"); exit(1); } - // XX use named arguments and getopt c3_d eve_d = 0; @@ -2935,6 +2934,10 @@ main(c3_i argc, _main_init(); +#if defined(U3_OS_osx) + darwin_register_mach_exception_handler(); +#endif + c3_c* bin_c = strdup(argv[0]); // parse for subcommands diff --git a/pkg/vere/platform/darwin/mach.c b/pkg/vere/platform/darwin/mach.c new file mode 100644 index 0000000000..9775882d2e --- /dev/null +++ b/pkg/vere/platform/darwin/mach.c @@ -0,0 +1,28 @@ +#include "log.h" + +#include +#include +#include +#include + + +// lldb does not listen to BSD signals, it only listens to Mach exceptions. +// The Mach exception EXC_BAD_ACCESS corresponds to SIGSEGV, but lldb has +// problems converting between them because of a longstanding macOS kernel bug. +// This means that without this workaround we cannot debug our binaries with +// lldb. The first segfault we hit causes an infinite loop in lldb no matter +// how many times you try to continue. This workaround is implemented in projects +// such as the Go runtime. +// See https://bugs.llvm.org/show_bug.cgi?id=22868#c1 for more details. + +void darwin_register_mach_exception_handler() { + kern_return_t kr = task_set_exception_ports( + mach_task_self(), + EXC_MASK_BAD_ACCESS, // SIGSEGV + MACH_PORT_NULL, + EXCEPTION_STATE_IDENTITY, + MACHINE_THREAD_STATE); + if ( KERN_SUCCESS != kr) { + u3l_log("mach: unable to register exception handler"); + } +} diff --git a/pkg/vere/vere.h b/pkg/vere/vere.h index 2b64e0c7c7..f97a76f142 100644 --- a/pkg/vere/vere.h +++ b/pkg/vere/vere.h @@ -1557,6 +1557,13 @@ void u3_daemon_init(); +#if defined(U3_OS_osx) + /* darwin_register_mach_exception_handler(): make lldb work + */ + void + darwin_register_mach_exception_handler(); +#endif + /* u3_write_fd(): retry interrupts, continue partial writes, assert errors. */ void