Skip to content

Commit

Permalink
Some signal safety and refactoring, also don't LD_PRELOAD for the tra…
Browse files Browse the repository at this point in the history
…cer program (#4)
  • Loading branch information
jeremy-rifkin authored Sep 6, 2024
1 parent 02ee505 commit 6bc7929
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 23 deletions.
11 changes: 0 additions & 11 deletions libSegFault/config.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
#include <cstdlib>
#include <cstring>

const char *getTracerProgram()
{
static const char *emptystr = "";
if (const char *value = getenv("LIBSEGFAULT_TRACER"))
{
return value;
}

return emptystr;
}

bool isDebugMode()
{
if (const char *value = getenv("LIBSEGFAULT_DEBUG"))
Expand Down
1 change: 0 additions & 1 deletion libSegFault/config.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once

bool isDebugMode();
const char *getTracerProgram();
bool useAlternativeStack();
bool dumpRegisters();
bool dumpMemory();
8 changes: 5 additions & 3 deletions libSegFault/segfault.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
#include <register-dump.h>
#include <sigcontextinfo.h>

#include "signal-safe-trace.hpp"
#include "config.hpp"
#include "signal-safe-trace.hpp"

#ifdef SA_SIGINFO
#define SIGCONTEXT siginfo_t *info, void *
Expand All @@ -59,6 +59,8 @@ static void write_strsignal(int fd, int signal)
TEMP_FAILURE_RETRY(write(fd, ptr, &buf[sizeof(buf)] - ptr));
}

const auto dump_registers = dumpRegisters();
const auto dump_memory = dumpMemory();

/* This function is called when a segmentation fault is caught. The system
is in an unstable state now. This means especially that malloc() might
Expand All @@ -85,7 +87,7 @@ static void catch_segfault(int signal, SIGCONTEXT ctx)
WRITE_STRING("\n");

#ifdef REGISTER_DUMP
if (dumpRegisters())
if (dump_registers)
{
REGISTER_DUMP;
}
Expand All @@ -96,7 +98,7 @@ static void catch_segfault(int signal, SIGCONTEXT ctx)
do_signal_safe_trace();

#ifdef HAVE_PROC_SELF
if (dumpMemory())
if (dump_memory)
{
/* Now the link map. */
int mapfd = open("/proc/self/maps", O_RDONLY);
Expand Down
50 changes: 42 additions & 8 deletions libSegFault/signal-safe-trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <iostream>
#include <string>
#include <string_view>
#include <vector>

#include <csignal>
#include <cstring>
Expand Down Expand Up @@ -41,17 +42,52 @@ void warmup_cpptrace()
cpptrace::get_safe_object_frame(buffer[0], &frame);
}

std::string tracer_program = []
{
const char *value = getenv("LIBSEGFAULT_TRACER");
return value ? value : "";
}();

extern char **environ;

std::vector<std::string> tracer_env = []
{
std::vector<std::string> tracer_env;
for (char **s = environ; *s; s++)
{
std::string_view var = *s;
if (!var.starts_with("LD_PRELOAD="))
{
tracer_env.emplace_back(var);
}
}
return tracer_env;
}();

const std::vector<char *> tracer_env_buffer = []
{
std::vector<char *> tracer_env_buffer;
for (auto &var : tracer_env)
{
tracer_env_buffer.emplace_back(var.data());
}
tracer_env_buffer.emplace_back(nullptr);
return tracer_env_buffer;
}();

const bool is_debug = isDebugMode();

[[gnu::constructor]] void init()
{
warmup_cpptrace();
}

const auto fork_failure_message = "fork() failed, unable to collect trace\n"sv;
const auto no_tracer_message = "exec(signal_tracer) failed: Please supply the environment variable LIBSEGFAULT_TRACER.\n"sv;
const auto no_tracer_message = "exec(signal_tracer) failed: Please supply the environment variable "
"LIBSEGFAULT_TRACER.\n"sv;

const auto exec_failure_message =
"exec(signal_tracer) failed: Make sure the signal_tracer exists and the executable permissions are correct.\n"sv;
const auto exec_failure_message = "exec(signal_tracer) failed: Make sure the signal_tracer exists and the executable "
"permissions are correct.\n"sv;

void do_signal_safe_trace()
{
Expand All @@ -74,21 +110,19 @@ void do_signal_safe_trace()
close(input_pipe.read_end);
close(input_pipe.write_end);

bool is_debug = isDebugMode();
const char *tracer_program = getTracerProgram();
if (strlen(tracer_program) == 0)
if (tracer_program.size() == 0)
{
std::ignore = write(STDERR_FILENO, no_tracer_message.data(), no_tracer_message.size());
}
else
{
execl(tracer_program, tracer_program, nullptr);
execle(tracer_program.c_str(), tracer_program.c_str(), nullptr, tracer_env_buffer.data());

if (is_debug)
{
auto errcode = errno;
fprintf(stderr, "errno: %d\n", errcode);
fprintf(stderr, "tried to execute: %s\n", tracer_program);
fprintf(stderr, "tried to execute: %s\n", tracer_program.c_str());
}

// https://linux.die.net/man/3/execl - execl() only returns when an error has occured
Expand Down

0 comments on commit 6bc7929

Please sign in to comment.