123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- /**
- * Copyright (c) 2022 Xiaomi Corporation (authors: Fangjun Kuang)
- *
- * See LICENSE for clarification regarding multiple authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /*
- * Stack trace related stuff is from kaldi.
- * Refer to
- * https://github.com/kaldi-asr/kaldi/blob/master/src/base/kaldi-error.cc
- */
- #include "log.h"
- #ifdef KNF_HAVE_EXECINFO_H
- #include <execinfo.h> // To get stack trace in error messages.
- #ifdef KNF_HAVE_CXXABI_H
- #include <cxxabi.h> // For name demangling.
- // Useful to decode the stack trace, but only used if we have execinfo.h
- #endif // KNF_HAVE_CXXABI_H
- #endif // KNF_HAVE_EXECINFO_H
- #include <stdlib.h>
- #include <ctime>
- #include <iomanip>
- #include <string>
- namespace knf {
- std::string GetDateTimeStr() {
- std::ostringstream os;
- std::time_t t = std::time(nullptr);
- std::tm tm = *std::localtime(&t);
- os << std::put_time(&tm, "%F %T"); // yyyy-mm-dd hh:mm:ss
- return os.str();
- }
- static bool LocateSymbolRange(const std::string &trace_name, std::size_t *begin,
- std::size_t *end) {
- // Find the first '_' with leading ' ' or '('.
- *begin = std::string::npos;
- for (std::size_t i = 1; i < trace_name.size(); ++i) {
- if (trace_name[i] != '_') {
- continue;
- }
- if (trace_name[i - 1] == ' ' || trace_name[i - 1] == '(') {
- *begin = i;
- break;
- }
- }
- if (*begin == std::string::npos) {
- return false;
- }
- *end = trace_name.find_first_of(" +", *begin);
- return *end != std::string::npos;
- }
- #ifdef KNF_HAVE_EXECINFO_H
- static std::string Demangle(const std::string &trace_name) {
- #ifndef KNF_HAVE_CXXABI_H
- return trace_name;
- #else // KNF_HAVE_CXXABI_H
- // Try demangle the symbol. We are trying to support the following formats
- // produced by different platforms:
- //
- // Linux:
- // ./kaldi-error-test(_ZN5kaldi13UnitTestErrorEv+0xb) [0x804965d]
- //
- // Mac:
- // 0 server 0x000000010f67614d _ZNK5kaldi13MessageLogger10LogMessageEv + 813
- //
- // We want to extract the name e.g., '_ZN5kaldi13UnitTestErrorEv' and
- // demangle it info a readable name like kaldi::UnitTextError.
- std::size_t begin, end;
- if (!LocateSymbolRange(trace_name, &begin, &end)) {
- return trace_name;
- }
- std::string symbol = trace_name.substr(begin, end - begin);
- int status;
- char *demangled_name = abi::__cxa_demangle(symbol.c_str(), 0, 0, &status);
- if (status == 0 && demangled_name != nullptr) {
- symbol = demangled_name;
- free(demangled_name);
- }
- return trace_name.substr(0, begin) + symbol +
- trace_name.substr(end, std::string::npos);
- #endif // KNF_HAVE_CXXABI_H
- }
- #endif // KNF_HAVE_EXECINFO_H
- std::string GetStackTrace() {
- std::string ans;
- #ifdef KNF_HAVE_EXECINFO_H
- constexpr const std::size_t kMaxTraceSize = 50;
- constexpr const std::size_t kMaxTracePrint = 50; // Must be even.
- // Buffer for the trace.
- void *trace[kMaxTraceSize];
- // Get the trace.
- std::size_t size = backtrace(trace, kMaxTraceSize);
- // Get the trace symbols.
- char **trace_symbol = backtrace_symbols(trace, size);
- if (trace_symbol == nullptr) return ans;
- // Compose a human-readable backtrace string.
- ans += "[ Stack-Trace: ]\n";
- if (size <= kMaxTracePrint) {
- for (std::size_t i = 0; i < size; ++i) {
- ans += Demangle(trace_symbol[i]) + "\n";
- }
- } else { // Print out first+last (e.g.) 5.
- for (std::size_t i = 0; i < kMaxTracePrint / 2; ++i) {
- ans += Demangle(trace_symbol[i]) + "\n";
- }
- ans += ".\n.\n.\n";
- for (std::size_t i = size - kMaxTracePrint / 2; i < size; ++i) {
- ans += Demangle(trace_symbol[i]) + "\n";
- }
- if (size == kMaxTraceSize)
- ans += ".\n.\n.\n"; // Stack was too long, probably a bug.
- }
- // We must free the array of pointers allocated by backtrace_symbols(),
- // but not the strings themselves.
- free(trace_symbol);
- #endif // KNF_HAVE_EXECINFO_H
- return ans;
- }
- } // namespace knf
|