Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions common/server/crash-dump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@
#include "common/ucontext/ucontext-portable.h"
#include <ucontext.h>

struct crash_dump_buffer {
char scratchpad[1024];
size_t position;
};
using crash_dump_buffer_t = struct crash_dump_buffer;

static inline char crash_dump_half_byte_char(uint8_t hb) {
if (hb <= 9) {
return '0' + hb;
Expand Down Expand Up @@ -67,7 +61,7 @@ static inline void crash_dump_write_uint64(uint64_t value, crash_dump_buffer_t*
// Keep in mind that:
// * `ucontext_t_portable` -- using for more efficient user context manipulations (e.g. `swapcontext`, `getcontext`, `setcontext`, etc)
// * `ucontext_t` -- using in signal handlers for machine state extracting in debug purposes.
static inline void crash_dump_prepare_registers([[maybe_unused]] crash_dump_buffer_t* buffer, [[maybe_unused]] void* ucontext) {
void crash_dump_prepare_registers([[maybe_unused]] crash_dump_buffer_t* buffer, [[maybe_unused]] const ucontext_t* uc) {
#ifdef __x86_64__
#ifdef __APPLE__
const auto* uc = static_cast<ucontext_t*>(ucontext);
Expand All @@ -93,8 +87,6 @@ static inline void crash_dump_prepare_registers([[maybe_unused]] crash_dump_buff
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);
#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);
crash_dump_write_reg(LITERAL_WITH_LENGTH("RSP=0x"), uc->uc_mcontext.gregs[REG_RSP], buffer);
crash_dump_write_reg(LITERAL_WITH_LENGTH("RBP=0x"), uc->uc_mcontext.gregs[REG_RBP], buffer);
Expand Down Expand Up @@ -131,7 +123,7 @@ void crash_dump_write(void* ucontext) {

static crash_dump_buffer_t buffer;
buffer.position = 0;
crash_dump_prepare_registers(&buffer, ucontext);
crash_dump_prepare_registers(&buffer, static_cast<ucontext_t*>(ucontext));

assert(buffer.position < sizeof(buffer.scratchpad));
buffer.scratchpad[buffer.position++] = '\n';
Expand Down
14 changes: 14 additions & 0 deletions common/server/crash-dump.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,19 @@
// Distributed under the GPL v3 License, see LICENSE.notice.txt

#pragma once
#include <cstddef>
#include <cstdint>
#include <string_view>
#include <ucontext.h>

struct crash_dump_buffer_t { // NOLINT
char scratchpad[1024];
size_t position{0};

std::string_view get_content() const noexcept {
return std::string_view{scratchpad, position};
}
};

void crash_dump_prepare_registers(crash_dump_buffer_t* buffer, const ucontext_t* uc);
void crash_dump_write(void* ucontext);
24 changes: 20 additions & 4 deletions server/json-logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
#include <cinttypes>
#include <execinfo.h>
#include <fcntl.h>
#include <ucontext.h>
#include <unistd.h>
#include <memory>

#include "common/algorithms/find.h"
#include "common/fast-backtrace.h"
#include "common/server/crash-dump.h"
#include "common/wrappers/likely.h"
#include "common/ucontext/ucontext-portable.h"
#include "runtime/kphp-backtrace.h"
Expand Down Expand Up @@ -259,7 +262,7 @@ void JsonLogger::write_log_with_demangled_backtrace(vk::string_view message,int
}

void JsonLogger::write_log(vk::string_view message, int type, int64_t created_at,
void *const *trace, int64_t trace_size, bool uncaught) noexcept {
void *const *trace, int64_t trace_size, bool uncaught, void* ucontext) noexcept {
if (json_log_fd_ <= 0) {
return;
}
Expand All @@ -269,7 +272,7 @@ void JsonLogger::write_log(vk::string_view message, int type, int64_t created_at
}
assert(json_out_it != buffers_.end());

write_general_info(json_out_it, type, created_at, uncaught);
write_general_info(json_out_it, type, created_at, uncaught, ucontext);

json_out_it->append_key("trace").start<'['>();
for (int64_t i = 0; i < trace_size; i++) {
Expand Down Expand Up @@ -324,7 +327,7 @@ void JsonLogger::reset_buffers() noexcept {
}
}

void JsonLogger::write_general_info(JsonBuffer *json_out_it, int type, int64_t created_at, bool uncaught) {
void JsonLogger::write_general_info(JsonBuffer *json_out_it, int type, int64_t created_at, bool uncaught, void* ucontext) {
json_out_it->append_key("version").append_integer(release_version_);
json_out_it->append_key("hostname").append_string(hostname_);
json_out_it->append_key("type").append_integer(type);
Expand All @@ -348,12 +351,25 @@ void JsonLogger::write_general_info(JsonBuffer *json_out_it, int type, int64_t c
json_out_it->append_key("logname_id").append_integer(logname_id);
}
json_out_it->append_key("pid").append_integer(pid);
json_out_it->append_key("ppid").append_integer(ppid);
json_out_it->append_key("cluster").append_string(vk::singleton<ServerConfig>::get().get_cluster_name());
json_out_it->append_raw(uncaught ? R"json("uncaught":true)json" : R"json("uncaught":false)json");
json_out_it->finish<'}'>();

if (extra_info_available_) {
Comment thread
denisichh marked this conversation as resolved.
json_out_it->append_key("extra_info").start<'{'>().append_raw(extra_info_).finish<'}'>();
json_out_it->append_key("extra_info").start<'{'>().append_raw(extra_info_);
if (ucontext != nullptr) {
Comment thread
denisichh marked this conversation as resolved.
const auto* ucp = static_cast<ucontext_t*>(ucontext);

#if defined(__x86_64__) && !defined(__APPLE__)
json_out_it->append_key("CR2 register").append_hex_as_string(ucp->uc_mcontext.gregs[REG_CR2]);
#endif

crash_dump_buffer_t buffer{};
crash_dump_prepare_registers(std::addressof(buffer), ucp);
json_out_it->append_key("registers").append_string(buffer.get_content());
}
json_out_it->finish<'}'>();
}
}

4 changes: 2 additions & 2 deletions server/json-logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class JsonLogger : vk::not_copyable {
// ATTENTION: this functions are used in signal handlers, therefore they are expected to be safe for them
// Details: https://man7.org/linux/man-pages/man7/signal-safety.7.html
// todo: functions bellow use backtrace which isn't async-signal safety
void write_log(vk::string_view message, int type, int64_t created_at, void *const *trace, int64_t trace_size, bool uncaught) noexcept;
void write_log(vk::string_view message, int type, int64_t created_at, void *const *trace, int64_t trace_size, bool uncaught, void* ucontext = nullptr) noexcept;
void write_log_with_backtrace(vk::string_view message, int type) noexcept;
void write_log_with_script_backtrace(vk::string_view message, int type) noexcept;

Expand Down Expand Up @@ -112,6 +112,6 @@ class JsonLogger : vk::not_copyable {
};
std::array<JsonBuffer, 8> buffers_;

void write_general_info(JsonBuffer * json_out_it, int type, int64_t created_at, bool uncaught);
void write_general_info(JsonBuffer * json_out_it, int type, int64_t created_at, bool uncaught, void* ucontext = nullptr);
};

1 change: 1 addition & 0 deletions server/php-engine-vars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ double oom_handling_memory_ratio = 0.00;

int worker_id = -1;
int pid = -1;
int ppid = -1;
int master_pid = -1;

ProcessType process_type = ProcessType::master;
Expand Down
1 change: 1 addition & 0 deletions server/php-engine-vars.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extern double oom_handling_memory_ratio;

extern int worker_id;
extern int pid;
extern int ppid;
extern int master_pid;

extern ProcessType process_type;
Expand Down
1 change: 1 addition & 0 deletions server/php-engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2381,6 +2381,7 @@ void init_default() {
now = (int)time(nullptr);

pid = getpid();
ppid = getppid();
master_pid = getpid();
// RPC part
PID.port = -1; // TODO: get rid of this?
Expand Down
1 change: 1 addition & 0 deletions server/php-master.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,7 @@ int run_worker(WorkerType worker_type) {
//verbosity = 0;
verbosity = initial_verbosity;
pid = getpid();
ppid = getppid();

master_sfd = -1;
if (worker_type == WorkerType::job_worker) {
Expand Down
6 changes: 3 additions & 3 deletions server/signal-handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ void sigsegv_handler(int signum, siginfo_t *info, void *ucontext) {
}
} else {
const char *msg = signum == SIGBUS ? "SIGBUS terminating program" : "SIGSEGV terminating program";
vk::singleton<JsonLogger>::get().write_log(msg, static_cast<int>(ServerLog::Critical), cur_time, trace, trace_size, true);
vk::singleton<JsonLogger>::get().write_log(msg, static_cast<int>(ServerLog::Critical), cur_time, trace, trace_size, true, ucontext);
vk::singleton<JsonLogger>::get().fsync_log_file();
write_str(2, "Error -2: Segmentation fault\n");
print_http_data();
Expand All @@ -206,15 +206,15 @@ void sigsegv_handler(int signum, siginfo_t *info, void *ucontext) {
}
}

void sigabrt_handler(int, siginfo_t *info, void *) {
void sigabrt_handler(int, siginfo_t *info, void *ucontext) {
const int64_t cur_time = time(nullptr);
void *trace[64];
const int trace_size = backtrace(trace, 64);
vk::string_view msg{dl_get_assert_message()};
if (msg.empty()) {
msg = "SIGABRT terminating program";
}
vk::singleton<JsonLogger>::get().write_log(msg, static_cast<int>(ServerLog::Critical), cur_time, trace, trace_size, true);
vk::singleton<JsonLogger>::get().write_log(msg, static_cast<int>(ServerLog::Critical), cur_time, trace, trace_size, true, ucontext);
vk::singleton<JsonLogger>::get().fsync_log_file();

print_prologue(cur_time);
Expand Down
6 changes: 6 additions & 0 deletions tests/python/lib/kphp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,13 @@ def _process_json_log(self, log_record):
del log_record["tags"]["logname_id"]
del log_record["tags"]["process_type"]
del log_record["tags"]["pid"]
del log_record["tags"]["ppid"]
if not got_tags.get("cluster", ""):
raise RuntimeError("Got an empty cluster in json log: {}".format(got_tags))
del log_record["tags"]["cluster"]

if log_record.get("extra_info"):
log_record["extra_info"].pop("CR2 register", None)
log_record["extra_info"].pop("registers", None)

return log_record
Loading