Skip to content

Commit

Permalink
Improve error messages when LLVM_SYMBOLIZER is not set or not found.
Browse files Browse the repository at this point in the history
  • Loading branch information
kentonv committed Jun 3, 2023
1 parent 1623ebb commit 628ba56
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/workerd/util/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ wd_cc_library(
visibility = ["//visibility:public"],
deps = [
"@capnp-cpp//src/kj",
":sentry",
],
alwayslink = 1,
target_compatible_with = select({
Expand Down
32 changes: 26 additions & 6 deletions src/workerd/util/symbolizer.c++
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <kj/debug.h>
#include <kj/exception.h>
#include "dlfcn.h"
#include <workerd/util/sentry.h>

// Stack trace symbolizer. To use link this source to the binary.
// Current implementation shells out to $LLVM_SYMBOLIZER if it is defined.
Expand All @@ -21,7 +22,7 @@ namespace {
struct Subprocess {
// A simple subprocess wrapper with in/out pipes.

static kj::Maybe<Subprocess> exec(kj::StringPtr cmd) {
static kj::Maybe<Subprocess> exec(const char* argv[]) noexcept {
// Execute command with a shell.
// Since this is used during error handling we do not to try to free resources in
// case of errors.
Expand Down Expand Up @@ -61,7 +62,12 @@ struct Subprocess {
_exit(3 * errno);
}

execl("/bin/sh", "sh", "-c", cmd.cStr(), nullptr);
KJ_SYSCALL_HANDLE_ERRORS(execvp(argv[0], const_cast<char**>(argv))) {
case ENOENT:
_exit(2);
default:
KJ_FAIL_SYSCALL("execvp", error);
}
_exit(1);
}
}
Expand All @@ -84,11 +90,18 @@ struct Subprocess {
String stringifyStackTrace(ArrayPtr<void* const> trace) {
const char* llvmSymbolizer = getenv("LLVM_SYMBOLIZER");
if (llvmSymbolizer == nullptr) {
return kj::str("\n$LLVM_SYMBOLIZER not defined");
return kj::str("\nStack trace not symbolized because $LLVM_SYMBOLIZER is not set. To set it "
"for bazel tests, use e.g. `--test_env=LLVM_SYMBOLIZER=llvm-symbolizer`.");
}

auto cmd = kj::str(llvmSymbolizer, " --pretty-print --relativenames");
KJ_IF_MAYBE(subprocess, Subprocess::exec(cmd)) {
const char* argv[] = {
llvmSymbolizer,
"--pretty-print",
"--relativenames",
nullptr
};

KJ_IF_MAYBE(subprocess, Subprocess::exec(argv)) {
// write addresses as "CODE <file_name> <hex_address>" lines.
auto addrs = strArray(KJ_MAP(addr, trace) {
Dl_info info;
Expand Down Expand Up @@ -123,7 +136,14 @@ String stringifyStackTrace(ArrayPtr<void* const> trace) {
int status = subprocess->closeAndWait();
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0) {
KJ_LOG(ERROR, "bad exit code", WEXITSTATUS(status));
if (WEXITSTATUS(status) == 2) {
LOG_WARNING_ONCE(kj::str(llvmSymbolizer, " was not found. "
"To symbolize stack traces, install it in your $PATH or set $LLVM_SYMBOLIZER to the "
"location of the binary. When running tests under bazel, use "
"`--test_env=LLVM_SYMBOLIZER=<path>`."));
} else {
KJ_LOG(ERROR, "bad exit code", WEXITSTATUS(status));
}
return nullptr;
}
} else {
Expand Down

0 comments on commit 628ba56

Please # to comment.