diff --git a/CMakeLists.txt b/CMakeLists.txt index 50030d7d1e71e3818b225c52fade7b26a683330a..001ddb0d7eca707e5ad0cae5ea4640299f48eb5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,8 @@ include(${CMAKE_SOURCE_DIR}/cmake/options.cmake) include(${CMAKE_SOURCE_DIR}/cmake/check_requirements.cmake) include(${CMAKE_SOURCE_DIR}/cmake/ascend_variables.cmake) +SET (CMAKE_ENABLE_EXPORTS TRUE) + #generate code if(DEFINED ENV{ENABLE_GEN_CODE}) set(ENABLE_GEN_CODE $ENV{ENABLE_GEN_CODE}) diff --git a/cmake/options.cmake b/cmake/options.cmake index 45534d3a2bc983ec740ad12baf80ba18837cf699..5f04fd0b1cd19076939cafd3b27b0890c5ace227 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -82,6 +82,7 @@ endif() if(DEBUG_MODE) set(CMAKE_BUILD_TYPE "Debug") add_compile_definitions(MEM_REUSE_DEBUG) + add_compile_definitions(STACKTRACE_ADDR2LINE) else() set(CMAKE_BUILD_TYPE "Release") endif() diff --git a/mindspore/core/utils/log_adapter.cc b/mindspore/core/utils/log_adapter.cc index ea9413b122a41fc2c2e5f473210f04f9e72d89fd..33fb071d0754bdf6d5bcfad5b6e5f1ba302c1a3b 100644 --- a/mindspore/core/utils/log_adapter.cc +++ b/mindspore/core/utils/log_adapter.cc @@ -27,6 +27,12 @@ #include #include "utils/convert_utils_base.h" +#ifdef USING_LINUX +#include +#include +#include +#endif + // namespace to support utils module definition namespace mindspore { constexpr int kNameMaxLength = 18; @@ -41,6 +47,17 @@ enum MsLogLevel this_thread_max_log_level = MsLogLevel::kException; thread_local enum MsLogLevel this_thread_max_log_level = MsLogLevel::kException; #endif +#ifdef USING_LINUX +void SignalHandler(int iSignalNo) { + std::cout << "Received signal " << iSignalNo << std::endl; + std::cout << "----------------------------------------------------\n" + << "- C++ Call Stack: (For framework developers)\n " + << "----------------------------------------------------" << std::endl; + std::cout << get_stacktrace_string(generate_stacktrace()) << std::endl; + exit(iSignalNo); +} +#endif + #ifdef USE_GLOG #define google mindspore_private static std::string GetProcName() { @@ -308,10 +325,18 @@ void DisplayDevExceptionMessage(std::ostringstream &oss, const std::vector(slog_module_id), GetSlogLevel(log_level_), "[%s:%d] %s] %s", location_.file_, location_.line_, location_.func_, str_msg.c_str()); +#ifdef USING_LINUX + Dlog(static_cast(slog_module_id), GetSlogLevel(log_level_), "s", get_stacktrace_string(location.stacktrace_)); +#endif #endif } @@ -773,6 +801,15 @@ MS_CORE_API void common_log_init(void) { #endif mindspore::InitSubModulesLogLevel(); + +#ifdef USING_LINUX + // ::signal(SIGTERM, mindspore::SignalHandler); + ::signal(SIGSEGV, mindspore::SignalHandler); + ::signal(SIGABRT, mindspore::SignalHandler); + ::signal(SIGFPE, mindspore::SignalHandler); + ::signal(SIGBUS, mindspore::SignalHandler); + ::signal(SIGILL, mindspore::SignalHandler); +#endif } // shared lib init hook diff --git a/mindspore/core/utils/log_adapter.h b/mindspore/core/utils/log_adapter.h index f009e815582bd5c7f844abf99fb6b4c7573dfa87..ab254c44c8212566b608dce4c20dca86063dc8f8 100644 --- a/mindspore/core/utils/log_adapter.h +++ b/mindspore/core/utils/log_adapter.h @@ -37,6 +37,13 @@ #undef google #endif +#if !defined(_WIN32) && !defined(_WIN64) && !defined(__ANDROID__) && !defined(ANDROID) && !defined(__APPLE__) +#define USING_LINUX +#endif +#ifdef USING_LINUX +#include "stacktrace.h" +#endif + #undef SM_DEBUG // NOTICE: when relative path of 'log_adapter.h' changed, macro 'LOG_HDR_FILE_REL_PATH' must be changed @@ -126,11 +133,18 @@ static inline std::string SupportedExceptionsToString() { struct LocationInfo { LocationInfo(const char *file, int line, const char *func) : file_(file), line_(line), func_(func) {} +#ifdef USING_LINUX + LocationInfo(const char *file, int line, const char *func, const StackTrace &stacktrace) + : file_(file), line_(line), func_(func), stacktrace_(stacktrace) {} +#endif ~LocationInfo() = default; const char *file_; int line_; const char *func_; +#ifdef USING_LINUX + const StackTrace stacktrace_; +#endif }; template ::value, int>::type = 0> @@ -309,7 +323,19 @@ class MS_CORE_API LogWriter { ExceptionType exception_type_; bool is_internal_exception_; }; - +#ifdef USING_LINUX +#define MSLOG_IF(level, condition, excp_type) \ + !(condition) ? void(0) \ + : mindspore::LogWriter(mindspore::LocationInfo(FILE_NAME, __LINE__, __FUNCTION__, \ + generate_stacktrace()), \ + level, SUBMODULE_ID, excp_type) < mindspore::LogStream() + +#define MSLOG_THROW(excp_type, is_internal_exception) \ + mindspore::LogWriter( \ + mindspore::LocationInfo(FILE_NAME, __LINE__, __FUNCTION__, generate_stacktrace()), \ + mindspore::kException, SUBMODULE_ID, excp_type, is_internal_exception) ^ \ + mindspore::LogStream() +#else #define MSLOG_IF(level, condition, excp_type) \ !(condition) ? void(0) \ : mindspore::LogWriter(mindspore::LocationInfo(FILE_NAME, __LINE__, __FUNCTION__), level, SUBMODULE_ID, \ @@ -319,6 +345,7 @@ class MS_CORE_API LogWriter { mindspore::LogWriter(mindspore::LocationInfo(FILE_NAME, __LINE__, __FUNCTION__), mindspore::kException, \ SUBMODULE_ID, excp_type, is_internal_exception) ^ \ mindspore::LogStream() +#endif #define MATCH_LEVEL(level) \ static_cast(level) >= mindspore::g_ms_submodule_log_levels[SUBMODULE_ID] && \ diff --git a/mindspore/core/utils/stacktrace.h b/mindspore/core/utils/stacktrace.h new file mode 100644 index 0000000000000000000000000000000000000000..94b034b8ac05a106ba3bdbd14078c7ec8233d4de --- /dev/null +++ b/mindspore/core/utils/stacktrace.h @@ -0,0 +1,201 @@ +#ifndef MINDSPORE_CORE_UTILS_STACKTRACE_H_ +#define MINDSPORE_CORE_UTILS_STACKTRACE_H_ + +#ifdef USING_LINUX + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +// #include + +#define STACKTRACE_DEPTH 1024 +#define ADDR2LINE_MAX_STRLEN 1024 + +template +struct StackTrace { + std::shared_ptr> call_stack = nullptr; + size_t size = 0; +}; + +template +static inline StackTrace generate_stacktrace() { + std::shared_ptr> call_stack = std::make_shared>(); + size_t size = backtrace(call_stack->data(), max_depth); + return StackTrace{call_stack, size}; +} + +inline std::string demangle(const char *name) { + if (name == nullptr) { + return {}; + } + int status = -4; + std::unique_ptr res{abi::__cxa_demangle(name, NULL, NULL, &status), std::free}; + return (status == 0) ? res.get() : name; +} + +const unsigned char to_hex_array_bytes[] = "0123456789ABCDEF"; + +template +inline std::array to_hex_array(T addr) noexcept { + std::array ret = {"0x"}; + ret.back() = '\0'; + static_assert(!std::is_pointer::value); + + const std::size_t s = sizeof(T); + + char *out = ret.data() + s * 2 + 1; + + for (std::size_t i = 0; i < s; ++i) { + const unsigned char tmp_addr = (addr & 0xFFu); + *out = to_hex_array_bytes[tmp_addr & 0xF]; + --out; + *out = to_hex_array_bytes[tmp_addr >> 4]; + --out; + addr >>= 8; + } + + return ret; +} + +inline std::array to_hex_array(void *addr) noexcept { + return to_hex_array(reinterpret_cast::type>(addr)); +} + +class addr2line_pipe { + ::FILE *p; + ::pid_t pid; + + public: + explicit addr2line_pipe(const char *flag, const char *exec_path, const char *addr) noexcept : p(0), pid(0) { + int pdes[2]; + + char prog_name[] = "/usr/bin/addr2line"; + + char *argp[] = {prog_name, const_cast(flag), const_cast(exec_path), const_cast(addr), 0}; + + if (::pipe(pdes) < 0) { + return; + } + + pid = ::fork(); + switch (pid) { + case -1: + // Failed... + ::close(pdes[0]); + ::close(pdes[1]); + return; + + case 0: + // We are the child. + ::close(STDERR_FILENO); + ::close(pdes[0]); + if (pdes[1] != STDOUT_FILENO) { + ::dup2(pdes[1], STDOUT_FILENO); + } + + // Do not use `execlp()`, `execvp()`, and `execvpe()` here! + // `exec*p*` functions are vulnerable to PATH variable evaluation + // attacks. + ::execv(prog_name, argp); + ::_exit(127); + } + + p = ::fdopen(pdes[0], "r"); + ::close(pdes[1]); + } + + operator ::FILE *() const noexcept { return p; } + + ~addr2line_pipe() noexcept { + if (p) { + ::fclose(p); + int pstat = 0; + ::kill(pid, SIGKILL); + ::waitpid(pid, &pstat, 0); + } + } +}; + +inline std::string addr2line(const char *filename, const char *addr_offset) { + if (filename[0] == '\0') { + return ""; + } + + addr2line_pipe p("-Cpe", filename, addr_offset); + + if (!p) { + return ""; + } + + char data[ADDR2LINE_MAX_STRLEN]; + while (!::feof(p)) { + if (::fgets(data, sizeof(data), p)) { + if (data[0] == '?') { + return ""; + } + auto result = std::string(data); + result.pop_back(); + return result; + } else { + break; + } + } + return ""; +} +struct python_filter { + bool operator()(std::string_view filename) { + return filename == "python" || filename == "python3" || filename.find("libpython") != std::string::npos; + } +}; + +template +struct filename_filter { + bool operator()(std::string_view filename) { return (filters()(filename) || ...); } +}; +template +std::string get_stacktrace_string(const StackTrace &stacktrace) { + std::ostringstream sout; + backtrace_symbols(stacktrace.call_stack->data(), stacktrace.size); + Dl_info info; + for (size_t i = 1; i < stacktrace.size; ++i) { + if (dladdr((*stacktrace.call_stack)[i], &info) && info.dli_fname) { + if (info.dli_sname == nullptr and info.dli_fname == nullptr) { + continue; + } + if (filename_filter()(info.dli_fname)) { + continue; + } + + auto demangled = demangle(info.dli_sname); + auto addr_offset = to_hex_array(reinterpret_cast((*stacktrace.call_stack)[i]) - + reinterpret_cast(info.dli_fbase)); +#ifdef STACKTRACE_ADDR2LINE + auto source_info = addr2line(info.dli_fname, addr_offset.data()); +#else + std::string source_info{}; +#endif + sout << "#" << i - 1 << " " << (*stacktrace.call_stack)[i] << " in"; + if (!demangled.empty()) { + sout << " " << demangled; + } + if (info.dli_fname != nullptr) { + sout << " [" << info.dli_fname << " + " << addr_offset.data() << "]"; + } + if (!source_info.empty()) { + sout << " at " << source_info; + } + sout << std::endl; + } + } + return sout.str(); +} + +#endif +#endif // MINDSPORE_CORE_UTILS_STACKTRACE_H_