From d92520c3e20d799167640962f2323d5836d7cf66 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Fri, 4 Nov 2022 23:48:03 +0800 Subject: [PATCH] [posix] add backtrace support (#8358) This commit logs the backtrace when the Thread crashes on the Linux and Android. --- Android.mk | 4 +- src/posix/Makefile-posix | 1 + src/posix/platform/CMakeLists.txt | 3 + src/posix/platform/Makefile.am | 1 + src/posix/platform/backtrace.cpp | 170 +++++++++++++++++++ src/posix/platform/openthread-posix-config.h | 19 +++ src/posix/platform/platform-posix.h | 6 + src/posix/platform/system.cpp | 4 + 8 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 src/posix/platform/backtrace.cpp diff --git a/Android.mk b/Android.mk index 6081b3003..c07477e9c 100644 --- a/Android.mk +++ b/Android.mk @@ -385,6 +385,7 @@ LOCAL_SRC_FILES := \ src/lib/url/url.cpp \ src/posix/platform/alarm.cpp \ src/posix/platform/backbone.cpp \ + src/posix/platform/backtrace.cpp \ src/posix/platform/daemon.cpp \ src/posix/platform/entropy.cpp \ src/posix/platform/firewall.cpp \ @@ -615,7 +616,8 @@ LOCAL_CPPFLAGS := \ LOCAL_LDLIBS := \ -lanl \ -lrt \ - -lutil + -lutil \ + -rdynamic \ LOCAL_SRC_FILES := \ src/posix/cli_readline.cpp \ diff --git a/src/posix/Makefile-posix b/src/posix/Makefile-posix index 24c7a83fd..7d7b9a8e7 100644 --- a/src/posix/Makefile-posix +++ b/src/posix/Makefile-posix @@ -80,6 +80,7 @@ UPTIME ?= 1 COMMONCFLAGS := \ -g \ + -rdynamic \ $(NULL) # If the user has asserted COVERAGE, alter the configuration options diff --git a/src/posix/platform/CMakeLists.txt b/src/posix/platform/CMakeLists.txt index a219cc174..185a322b3 100644 --- a/src/posix/platform/CMakeLists.txt +++ b/src/posix/platform/CMakeLists.txt @@ -98,9 +98,12 @@ endif() set(OT_POSIX_CONFIG_RCP_VENDOR_INTERFACE "vendor_interface_example.cpp" CACHE STRING "vendor interface implementation") +set(CMAKE_EXE_LINKER_FLAGS "-rdynamic ${CMAKE_EXE_LINKER_FLAGS}" PARENT_SCOPE) + add_library(openthread-posix alarm.cpp backbone.cpp + backtrace.cpp daemon.cpp entropy.cpp firewall.cpp diff --git a/src/posix/platform/Makefile.am b/src/posix/platform/Makefile.am index ab7ae85f4..648278764 100644 --- a/src/posix/platform/Makefile.am +++ b/src/posix/platform/Makefile.am @@ -46,6 +46,7 @@ libopenthread_posix_a_CPPFLAGS = \ libopenthread_posix_a_SOURCES = \ alarm.cpp \ backbone.cpp \ + backtrace.cpp \ daemon.cpp \ entropy.cpp \ firewall.cpp \ diff --git a/src/posix/platform/backtrace.cpp b/src/posix/platform/backtrace.cpp new file mode 100644 index 000000000..45e3b5665 --- /dev/null +++ b/src/posix/platform/backtrace.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2022, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements backtrace for posix. + */ + +#include "openthread-posix-config.h" +#include "platform-posix.h" + +#include +#include +#include +#include +#include + +#include "common/code_utils.hpp" +#include "common/logging.hpp" + +#if OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE + +#if defined(__linux__) && !OPENTHREAD_ENABLE_ANDROID_NDK +#if OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE +#include +#include +#include + +class LogPrinter : public android::Printer +{ +public: + virtual void printLine(const char *string) { otLogCritPlat("%s", string); } +}; + +static void dumpStack(void) +{ + LogPrinter printer; + android::CallStack callstack; + + callstack.update(); + callstack.print(printer); +} +#else // OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE +#include +#include + +static void demangleSymbol(int aIndex, const char *aSymbol) +{ + constexpr uint16_t kMaxNameSize = 256; + int status; + char program[kMaxNameSize + 1]; + char mangledName[kMaxNameSize + 1]; + char * demangledName = nullptr; + char * functionName = nullptr; + unsigned int offset = 0; + unsigned int address = 0; + + // Try to demangle a C++ name + if (sscanf(aSymbol, "%256[^(]%*[^_]%256[^)+]%*[^0x]%x%*[^0x]%x", program, mangledName, &offset, &address) == 4) + { + demangledName = abi::__cxa_demangle(mangledName, nullptr, nullptr, &status); + functionName = demangledName; + } + + VerifyOrExit(demangledName == nullptr); + + // If failed to demangle a C++ name, try to get a regular C symbol + if (sscanf(aSymbol, "%256[^(](%256[^)+]%*[^0x]%x%*[^0x]%x", program, mangledName, &offset, &address) == 4) + { + functionName = mangledName; + } + +exit: + if (functionName != nullptr) + { + otLogCritPlat("#%2d: %s %s+0x%x [0x%x]\n", aIndex, program, functionName, offset, address); + } + else + { + otLogCritPlat("#%2d: %s\n", aIndex, aSymbol); + } + + if (demangledName != nullptr) + { + free(demangledName); + } +} + +static void dumpStack(void) +{ + constexpr uint8_t kMaxDepth = 50; + void * stack[kMaxDepth]; + char ** symbols; + int depth; + + depth = backtrace(stack, kMaxDepth); + symbols = backtrace_symbols(stack, depth); + VerifyOrExit(symbols != nullptr); + + for (int i = 0; i < depth; i++) + { + demangleSymbol(i, symbols[i]); + } + + free(symbols); + +exit: + return; +} +#endif // OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE + +static void signalCritical(int sig, siginfo_t *info, void *ucontext) +{ + OT_UNUSED_VARIABLE(ucontext); + OT_UNUSED_VARIABLE(info); + + otLogCritPlat("------------------ BEGINNING OF CRASH -------------"); + otLogCritPlat("*** FATAL ERROR: Caught signal: %d (%s)", sig, strsignal(sig)); + + dumpStack(); + + otLogCritPlat("------------------ END OF CRASH ------------------"); + exit(EXIT_FAILURE); +} + +void platformBacktraceInit(void) +{ + struct sigaction sigact; + + sigact.sa_sigaction = &signalCritical; + sigact.sa_flags = SA_RESTART | SA_SIGINFO | SA_NOCLDWAIT; + + sigaction(SIGABRT, &sigact, (struct sigaction *)nullptr); + sigaction(SIGILL, &sigact, (struct sigaction *)nullptr); + sigaction(SIGSEGV, &sigact, (struct sigaction *)nullptr); + sigaction(SIGBUS, &sigact, (struct sigaction *)nullptr); + sigaction(SIGTRAP, &sigact, (struct sigaction *)nullptr); + sigaction(SIGFPE, &sigact, (struct sigaction *)nullptr); +} +#else // defined(__linux__) && !OPENTHREAD_ENABLE_ANDROID_NDK +void platformBacktraceInit(void) +{ +} +#endif // defined(__linux__) && !OPENTHREAD_ENABLE_ANDROID_NDK +#endif // OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE diff --git a/src/posix/platform/openthread-posix-config.h b/src/posix/platform/openthread-posix-config.h index 34998464d..891ad7f45 100644 --- a/src/posix/platform/openthread-posix-config.h +++ b/src/posix/platform/openthread-posix-config.h @@ -304,4 +304,23 @@ #define OPENTHREAD_POSIX_CONFIG_NAT64_CIDR "192.168.255.0/24" #endif +/** + * @def OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE + * + * Define as 1 to enable backtrace support. + * + */ +#ifndef OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE +#define OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE 1 +#endif + +/** + * @def OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE + * + * Define as 1 to enable android support. + * + */ +#ifndef OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE +#define OPENTHREAD_POSIX_CONFIG_ANDROID_ENABLE 0 +#endif #endif // OPENTHREAD_PLATFORM_CONFIG_H_ diff --git a/src/posix/platform/platform-posix.h b/src/posix/platform/platform-posix.h index a3b21722d..9e2252a99 100644 --- a/src/posix/platform/platform-posix.h +++ b/src/posix/platform/platform-posix.h @@ -524,6 +524,12 @@ extern unsigned int gBackboneNetifIndex; */ bool platformInfraIfIsRunning(void); +/** + * This function initializes backtrace module. + * + */ +void platformBacktraceInit(void); + #ifdef __cplusplus } #endif diff --git a/src/posix/platform/system.cpp b/src/posix/platform/system.cpp index 6d836c094..1eb3e5946 100644 --- a/src/posix/platform/system.cpp +++ b/src/posix/platform/system.cpp @@ -123,6 +123,10 @@ static const char *getTrelRadioUrl(otPlatformConfig *aPlatformConfig) void platformInit(otPlatformConfig *aPlatformConfig) { +#if OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE + platformBacktraceInit(); +#endif + platformAlarmInit(aPlatformConfig->mSpeedUpFactor, aPlatformConfig->mRealTimeSignal); platformRadioInit(get802154RadioUrl(aPlatformConfig));