diff --git a/common/server/crash-dump.cpp b/common/server/crash-dump.cpp index 176ee93649..0a714ce1cc 100644 --- a/common/server/crash-dump.cpp +++ b/common/server/crash-dump.cpp @@ -14,12 +14,6 @@ #include "common/ucontext/ucontext-portable.h" #include -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; @@ -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); @@ -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); - 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); @@ -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)); assert(buffer.position < sizeof(buffer.scratchpad)); buffer.scratchpad[buffer.position++] = '\n'; diff --git a/common/server/crash-dump.h b/common/server/crash-dump.h index 53c1bf3d13..c67131525f 100644 --- a/common/server/crash-dump.h +++ b/common/server/crash-dump.h @@ -3,5 +3,19 @@ // Distributed under the GPL v3 License, see LICENSE.notice.txt #pragma once +#include +#include +#include +#include +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); diff --git a/server/json-logger.cpp b/server/json-logger.cpp index 1459c0e539..8a6a170fad 100644 --- a/server/json-logger.cpp +++ b/server/json-logger.cpp @@ -6,10 +6,13 @@ #include #include #include +#include #include +#include #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" @@ -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; } @@ -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++) { @@ -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); @@ -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::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_) { - 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) { + const auto* ucp = static_cast(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<'}'>(); } } diff --git a/server/json-logger.h b/server/json-logger.h index da56fc0883..305e87417f 100644 --- a/server/json-logger.h +++ b/server/json-logger.h @@ -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; @@ -112,6 +112,6 @@ class JsonLogger : vk::not_copyable { }; std::array 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); }; diff --git a/server/php-engine-vars.cpp b/server/php-engine-vars.cpp index 6ee5eb9bc1..3afe969565 100644 --- a/server/php-engine-vars.cpp +++ b/server/php-engine-vars.cpp @@ -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; diff --git a/server/php-engine-vars.h b/server/php-engine-vars.h index f194e74c7a..6111ad7cd8 100644 --- a/server/php-engine-vars.h +++ b/server/php-engine-vars.h @@ -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; diff --git a/server/php-engine.cpp b/server/php-engine.cpp index 16e18646e0..ab6221f29f 100644 --- a/server/php-engine.cpp +++ b/server/php-engine.cpp @@ -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? diff --git a/server/php-master.cpp b/server/php-master.cpp index e0df4879da..6b50a183f0 100644 --- a/server/php-master.cpp +++ b/server/php-master.cpp @@ -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) { diff --git a/server/signal-handlers.cpp b/server/signal-handlers.cpp index 422010eb49..7bfb3fcfd3 100644 --- a/server/signal-handlers.cpp +++ b/server/signal-handlers.cpp @@ -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::get().write_log(msg, static_cast(ServerLog::Critical), cur_time, trace, trace_size, true); + vk::singleton::get().write_log(msg, static_cast(ServerLog::Critical), cur_time, trace, trace_size, true, ucontext); vk::singleton::get().fsync_log_file(); write_str(2, "Error -2: Segmentation fault\n"); print_http_data(); @@ -206,7 +206,7 @@ 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); @@ -214,7 +214,7 @@ void sigabrt_handler(int, siginfo_t *info, void *) { if (msg.empty()) { msg = "SIGABRT terminating program"; } - vk::singleton::get().write_log(msg, static_cast(ServerLog::Critical), cur_time, trace, trace_size, true); + vk::singleton::get().write_log(msg, static_cast(ServerLog::Critical), cur_time, trace, trace_size, true, ucontext); vk::singleton::get().fsync_log_file(); print_prologue(cur_time); diff --git a/tests/python/lib/kphp_server.py b/tests/python/lib/kphp_server.py index 113f70a571..d91182dbb1 100644 --- a/tests/python/lib/kphp_server.py +++ b/tests/python/lib/kphp_server.py @@ -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