From 8640cf52d17b541efdcd557eed40e63aa3ca3952 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Thu, 26 Dec 2024 12:33:48 -0800 Subject: [PATCH] Switch to abseil symbolization / stack tracing routines Signed-off-by: Anton Korobeynikov --- CMakeLists.txt | 1 - backends/bmv2/simple_switch/main.cpp | 2 + cmake/config.h.cmake | 3 -- lib/CMakeLists.txt | 2 + lib/alloc_trace.cpp | 36 +++++++-------- lib/backtrace_exception.cpp | 41 +++++++++-------- lib/backtrace_exception.h | 11 +---- lib/crash.cpp | 67 +++++++++++++--------------- lib/gc.cpp | 21 ++++----- lib/gc.h | 4 +- 10 files changed, 85 insertions(+), 103 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc21ef31e76..f519916729a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -240,7 +240,6 @@ list (APPEND P4C_LIB_DEPS ${P4C_ABSL_LIBRARIES}) p4c_add_library (rt clock_gettime HAVE_CLOCK_GETTIME) # Check includes. -check_include_file(execinfo.h HAVE_EXECINFO_H) check_include_file(ucontext.h HAVE_UCONTEXT_H) check_include_file(backtrace-supported.h HAVE_LIBBACKTRACE) check_include_file_cxx(mm_malloc.h HAVE_MM_MALLOC_H) diff --git a/backends/bmv2/simple_switch/main.cpp b/backends/bmv2/simple_switch/main.cpp index 0458cc2caab..aaaa5aa0b44 100644 --- a/backends/bmv2/simple_switch/main.cpp +++ b/backends/bmv2/simple_switch/main.cpp @@ -32,6 +32,7 @@ limitations under the License. #include "ir/json_generator.h" #include "ir/json_loader.h" #include "lib/algorithm.h" +#include "lib/crash.h" #include "lib/error.h" #include "lib/exceptions.h" #include "lib/gc.h" @@ -42,6 +43,7 @@ using namespace P4; int main(int argc, char *const argv[]) { setup_gc_logging(); + setup_signals(); AutoCompileContext autoBMV2Context(new BMV2::SimpleSwitchContext); auto &options = BMV2::SimpleSwitchContext::get().options(); diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake index 11de85d8eae..661a54576aa 100644 --- a/cmake/config.h.cmake +++ b/cmake/config.h.cmake @@ -4,9 +4,6 @@ /* Define to 1 if you have the boost graph headers */ #cmakedefine HAVE_LIBBOOST_GRAPH 1 -/* Define to 1 if you have the execinfo.h header */ -#cmakedefine HAVE_EXECINFO_H 1 - /* Define to 1 if you have libbacktrace */ #cmakedefine HAVE_LIBBACKTRACE 1 diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 21204b63dcf..8494fa5bb6f 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -94,6 +94,8 @@ add_library(p4ctoolkit STATIC ${LIBP4CTOOLKIT_SRCS}) # Disable libcall (realloc, malloc) optimizations which may cause infinite loops. set_target_properties(p4ctoolkit PROPERTIES COMPILE_FLAGS -fno-builtin) target_link_libraries(p4ctoolkit + PRIVATE absl::stacktrace + PRIVATE absl::symbolize # These libraries are exposed by a header. PUBLIC absl::bits PUBLIC absl::strings diff --git a/lib/alloc_trace.cpp b/lib/alloc_trace.cpp index 4347dacb93d..0e719cf0012 100644 --- a/lib/alloc_trace.cpp +++ b/lib/alloc_trace.cpp @@ -1,12 +1,10 @@ #include "alloc_trace.h" +#include "absl/debugging/symbolize.h" #include "hex.h" #include "log.h" #include "n4.h" -#if HAVE_EXECINFO_H -#include -#endif #if HAVE_LIBBACKTRACE #include @@ -45,15 +43,11 @@ int bt_print_callback(void *out_, uintptr_t pc, const char *file, int line, cons file = "??"; } out << Log::endl << file << ":" << line; + if (func) { -#if HAVE_CXXABI_H - int status; - if (char *fn = abi::__cxa_demangle(func, 0, 0, &status)) { - if (strlen(fn) < 100) out << " (" << fn << ")"; - free(fn); - } else -#endif - out << " (" << func << ")"; + char tmp[1024]; + if (absl::Symbolize((void *)pc, tmp, sizeof(tmp))) func = tmp; + out << " (" << func << ")"; } out << " [" << hex(pc) << "]"; return 0; @@ -69,7 +63,7 @@ std::ostream &operator<<(std::ostream &out, const AllocTrace &at) { #if HAVE_LIBGC PauseTrace temp_pause; #endif - typedef decltype(at.data)::value_type data_t; + using data_t = decltype(at.data)::value_type; std::vector> sorted; size_t total_total = 0; for (auto &e : at.data) { @@ -83,14 +77,15 @@ std::ostream &operator<<(std::ostream &out, const AllocTrace &at) { if (!global_backtrace_state) global_backtrace_state = backtrace_create_state(exename(), 1, bt_error, &out); #endif + out << "Allocated a total of " << n4(total_total) << "B memory"; for (auto &s : sorted) { - if (s.first < 1000000) break; // ignore little stuff + if (s.first < 1000000) break; // ignore little stuff size_t count = 0; for (auto &al : s.second->second) count += al.second; out << Log::endl << "allocated " << n4(s.first) << "B in " << count << " calls"; -#if HAVE_EXECINFO_H out << " from:" << Log::indent; + #if HAVE_LIBBACKTRACE for (int i = 1; i < ALLOC_TRACE_DEPTH; ++i) { /* due to calling the callback multiple times for inlined functions, we need to @@ -100,15 +95,18 @@ std::ostream &operator<<(std::ostream &out, const AllocTrace &at) { bt_print_callback, bt_error, &out); } #else - char **syms = backtrace_symbols(s.second->first.trace, ALLOC_TRACE_DEPTH); + char tmp[1024]; for (int i = ALLOC_TRACE_DEPTH - 1; i >= 1; --i) { - const char *alt = addr2line(s.second->first.trace[i], syms[i]); - out << Log::endl << (alt ? alt : syms[i]) << ' ' << s.second->first.trace[i]; + void *pc = s.second->first.trace[i]; + const char *symbol = "(unknown)"; + if (absl::Symbolize(pc, tmp, sizeof(tmp))) { + symbol = tmp; + } + const char *alt = addr2line(pc, nullptr); + out << "\n " << (alt ? alt : "??: ") << symbol << " [" << hex(pc) << "]"; } - free(syms); #endif out << Log::unindent; -#endif } return out; } diff --git a/lib/backtrace_exception.cpp b/lib/backtrace_exception.cpp index 75ed9e693c9..9be820a6cbe 100644 --- a/lib/backtrace_exception.cpp +++ b/lib/backtrace_exception.cpp @@ -21,12 +21,12 @@ limitations under the License. #include #endif -#include #include +#include #include #include -#include +#include "absl/debugging/symbolize.h" #include "crash.h" #include "exename.h" #include "hex.h" @@ -38,40 +38,39 @@ extern struct backtrace_state *global_backtrace_state; int append_message(void *msg_, uintptr_t pc, const char *file, int line, const char *func) { std::string &msg = *static_cast(msg_); - std::stringstream tmp; - tmp << "\n 0x" << hex(pc) << " " << (func ? func : "??"); - if (file) tmp << "\n " << file << ":" << line; - msg += tmp.str(); + std::stringstream str; + char *demangled = nullptr; + char tmp[1024]; + if (func && absl::Symbolize((void *)pc, tmp, sizeof(tmp))) demangled = tmp; + str << "\n 0x" << hex(pc) << " " << (demangled ? demangled : func ? func : "??"); + if (file) str << "\n " << file << ":" << line; + msg += str.str(); return 0; } #endif void backtrace_fill_stacktrace(std::string &msg, void *const *backtrace, int size) { - // backtrace_symbols is only available with libexecinfo #if HAVE_LIBBACKTRACE if (!global_backtrace_state) global_backtrace_state = backtrace_create_state(exename(), 1, nullptr, nullptr); backtrace_full(global_backtrace_state, 1, append_message, nullptr, &msg); (void)backtrace; (void)size; -#elif HAVE_EXECINFO_H - char **strings = backtrace_symbols(backtrace, size); +#else + char tmp[1024]; + std::stringstream str; for (int i = 0; i < size; i++) { - if (strings) { - msg += "\n "; - msg += strings[i]; + void *pc = backtrace[i]; + const char *symbol = "??"; + if (absl::Symbolize(pc, tmp, sizeof(tmp))) { + symbol = tmp; } - if (const char *line = addr2line(backtrace[i], strings ? strings[i] : 0)) { - msg += "\n "; - msg += line; + str << "\n 0x" << hex(pc) << " " << symbol; + if (const char *line = addr2line(pc, nullptr)) { + str << "\n " << line; } + msg += str.str(); } - free(strings); -#else - // unused - (void)msg; - (void)backtrace; - (void)size; #endif } diff --git a/lib/backtrace_exception.h b/lib/backtrace_exception.h index 5c5ee064fed..ac8d533924d 100644 --- a/lib/backtrace_exception.h +++ b/lib/backtrace_exception.h @@ -20,12 +20,9 @@ limitations under the License. #include #include +#include "absl/debugging/stacktrace.h" #include "config.h" -#if HAVE_EXECINFO_H -#include -#endif - namespace P4 { void backtrace_fill_stacktrace(std::string &msg, void *const *backtrace, int size); @@ -40,11 +37,7 @@ class backtrace_exception : public E { public: template explicit backtrace_exception(Args &&...args) : E(std::forward(args)...) { -#if HAVE_EXECINFO_H - backtrace_size = backtrace(backtrace_buffer, buffer_size); -#else - backtrace_size = 0; -#endif + backtrace_size = absl::GetStackTrace(backtrace_buffer, buffer_size, 1); } const char *what() const noexcept { diff --git a/lib/crash.cpp b/lib/crash.cpp index 766cabd3bf4..0aefa964f2f 100644 --- a/lib/crash.cpp +++ b/lib/crash.cpp @@ -16,16 +16,14 @@ limitations under the License. #include "crash.h" #include -#include -#if HAVE_EXECINFO_H -#include -#endif #include -#include -#include -#include #include + +#include +#include +#include +#include #if HAVE_UCONTEXT_H #include #endif @@ -33,11 +31,6 @@ limitations under the License. #if HAVE_LIBBACKTRACE #include #endif -#if HAVE_CXXABI_H -#include -#endif - -#include #ifdef MULTITHREAD #include @@ -45,6 +38,8 @@ limitations under the License. #include #endif +#include "absl/debugging/stacktrace.h" +#include "absl/debugging/symbolize.h" #include "exceptions.h" #include "exename.h" #include "hex.h" @@ -87,20 +82,17 @@ static void sigint_shutdown(int sig, siginfo_t *, void *) { #if HAVE_LIBBACKTRACE static int backtrace_log(void *, uintptr_t pc, const char *fname, int lineno, const char *func) { char *demangled = nullptr; -#if HAVE_CXXABI_H - int status; - demangled = func ? abi::__cxa_demangle(func, 0, 0, &status) : nullptr; -#endif + char tmp[1024]; + if (func && absl::Symbolize((void *)pc, tmp, sizeof(tmp))) demangled = tmp; LOG1(" 0x" << hex(pc) << " " << (demangled ? demangled : func ? func : "??")); - free(demangled); if (fname) { LOG1(" " << fname << ":" << lineno); } return 0; } static void backtrace_error(void *, const char *msg, int) { perror(msg); } +#endif -#elif HAVE_EXECINFO_H /* * call external program addr2line WITHOUT using malloc or stdio or anything * else that might be problematic if there's memory corruption or exhaustion @@ -170,7 +162,8 @@ const char *addr2line(void *addr, const char *text) { close(pfd2[0]); to_child = pfd2[1]; } - if (child == -1) return 0; + if (child == -1) return nullptr; + char *p = buffer; uintptr_t a = (uintptr_t)addr; int shift = (CHAR_BIT * sizeof(uintptr_t) - 1) & ~3; @@ -180,8 +173,8 @@ const char *addr2line(void *addr, const char *text) { shift -= 4; } *p++ = '\n'; - auto _unused = write(to_child, buffer, p - buffer); - (void)_unused; + auto written = write(to_child, buffer, p - buffer); + if (written != p - buffer) return nullptr; p = buffer; int len; while (p < buffer + sizeof(buffer) - 1 && @@ -190,10 +183,9 @@ const char *addr2line(void *addr, const char *text) { } *p = 0; if ((p = strchr(buffer, '\n'))) *p = 0; - if (buffer[0] == 0 || buffer[0] == '?') return 0; + if (buffer[0] == 0 || buffer[0] == '?') return nullptr; return buffer; } -#endif /* HAVE_EXECINFO_H */ #if HAVE_UCONTEXT_H @@ -278,24 +270,25 @@ static void crash_shutdown(int sig, siginfo_t *info, void *uctxt) { (void)uctxt; // Suppress unused parameter warning. #endif -#if HAVE_LIBBACKTRACE if (LOGGING(1)) { +#if HAVE_LIBBACKTRACE backtrace_full(global_backtrace_state, 1, backtrace_log, backtrace_error, nullptr); - } -#elif HAVE_EXECINFO_H - if (LOGGING(1)) { +#else static void *buffer[64]; - int size = backtrace(buffer, 64); - char **strings = backtrace_symbols(buffer, size); - for (int i = 1; i < size; i++) { - if (strings) LOG1(" " << strings[i]); - if (const char *line = addr2line(buffer[i], strings ? strings[i] : 0)) - LOG1(" " << line); + static char tmp[1024]; + int size = absl::GetStackTrace(buffer, 64, 1); + for (int i = 0; i < size; i++) { + void *pc = buffer[i]; + const char *symbol = "(unknown)"; + if (absl::Symbolize(pc, tmp, sizeof(tmp))) { + symbol = tmp; + } + const char *alt = addr2line(pc, nullptr); + LOG1(" 0x" << hex(pc) << " " << (alt ? alt : symbol)); } if (size < 1) LOG1("backtrace failed"); - free(strings); - } #endif + } MTONLY( if (++threads_dumped < int(thread_ids.size())) { lock.unlock(); @@ -314,6 +307,7 @@ void setup_signals() { sigaction(SIGINT, &sigact, 0); sigaction(SIGQUIT, &sigact, 0); sigaction(SIGTERM, &sigact, 0); + sigact.sa_sigaction = crash_shutdown; sigaction(SIGILL, &sigact, 0); sigaction(SIGABRT, &sigact, 0); @@ -322,9 +316,12 @@ void setup_signals() { sigaction(SIGBUS, &sigact, 0); sigaction(SIGTRAP, &sigact, 0); signal(SIGPIPE, SIG_IGN); + #if HAVE_LIBBACKTRACE if (LOGGING(1)) global_backtrace_state = backtrace_create_state(exename(), 1, nullptr, nullptr); #endif + + absl::InitializeSymbolizer(exename()); } } // namespace P4 diff --git a/lib/gc.cpp b/lib/gc.cpp index 656fba83fae..26be7d9b189 100644 --- a/lib/gc.cpp +++ b/lib/gc.cpp @@ -34,14 +34,12 @@ limitations under the License. #include #endif /* HAVE_LIBGC */ #include -#if HAVE_EXECINFO_H -#include -#endif #include #include #include +#include "absl/debugging/stacktrace.h" #include "backtrace_exception.h" #include "cstring.h" #include "log.h" @@ -61,16 +59,13 @@ static char *emergency_ptr; static alloc_trace_cb_t trace_cb; static bool tracing = false; -#if !HAVE_EXECINFO_H -#define backtrace(BUFFER, SIZE) memset(BUFFER, 0, (SIZE) * sizeof(void *)) -#endif -#define TRACE_ALLOC(size) \ - if (trace_cb.fn && !tracing) { \ - void *buffer[ALLOC_TRACE_DEPTH]; \ - tracing = true; \ - backtrace(buffer, ALLOC_TRACE_DEPTH); \ - trace_cb.fn(trace_cb.arg, buffer, size); \ - tracing = false; \ +#define TRACE_ALLOC(size) \ + if (trace_cb.fn && !tracing) { \ + void *buffer[ALLOC_TRACE_DEPTH]; \ + tracing = true; \ + absl::GetStackTrace(buffer, ALLOC_TRACE_DEPTH, 1); \ + trace_cb.fn(trace_cb.arg, buffer, size); \ + tracing = false; \ } static void maybe_initialize_gc() { diff --git a/lib/gc.h b/lib/gc.h index 0876508ac60..dc69de8d299 100644 --- a/lib/gc.h +++ b/lib/gc.h @@ -25,10 +25,10 @@ void setup_gc_logging(); size_t gc_mem_inuse(size_t *max = 0); // trigger GC, return inuse after struct alloc_trace_cb_t { - void (*fn)(void *, void **, size_t); + void (*fn)(void *arg, void **pc, size_t sz); void *arg; }; alloc_trace_cb_t set_alloc_trace(alloc_trace_cb_t cb); -alloc_trace_cb_t set_alloc_trace(void (*fn)(void *, void **, size_t), void *arg); +alloc_trace_cb_t set_alloc_trace(void (*fn)(void *arg, void **pc, size_t sz), void *arg); #endif /* LIB_GC_H_ */