From d170877dc38d6e46c571b82b91c3dd5b4b1a1417 Mon Sep 17 00:00:00 2001 From: yuhailong Date: Tue, 15 Jul 2025 22:19:09 +0800 Subject: [PATCH] feat:opt dfx_signal_handler interface Signed-off-by: yuhailong Change-Id: I25d67e12b7c43a6dedb1cba7900de54c79998c84 Signed-off-by: yuhailong --- bundle.json | 3 +- interfaces/common/dfx_define.h | 1 + interfaces/innerkits/async_stack/BUILD.gn | 1 + .../innerkits/async_stack/async_stack.cpp | 9 +- .../signal_handler/dfx_signal_handler.c | 16 ++- .../dfx_signalhandler_exception.c | 4 +- .../include/dfx_signal_handler.h | 124 +++++++++++------- .../include/dfx_unique_crash_obj.h | 80 +++++++++++ .../signal_handler/libdfx_signalhandler.map | 2 +- .../signal_handler/signal_handler_test.cpp | 12 +- tools/crasher_cpp/BUILD.gn | 7 +- tools/crasher_cpp/dfx_crasher.cpp | 45 ++----- 12 files changed, 193 insertions(+), 111 deletions(-) create mode 100644 interfaces/innerkits/signal_handler/include/dfx_unique_crash_obj.h diff --git a/bundle.json b/bundle.json index 3a919fcc6..8386e5575 100644 --- a/bundle.json +++ b/bundle.json @@ -112,7 +112,8 @@ "name": "//base/hiviewdfx/faultloggerd/interfaces/innerkits/signal_handler:dfx_signalhandler", "header": { "header_files": [ - "dfx_signal_handler.h" + "dfx_signal_handler.h", + "dfx_unique_crash_obj.h" ], "header_base": "//base/hiviewdfx/faultloggerd/interfaces/innerkits/signal_handler/include" } diff --git a/interfaces/common/dfx_define.h b/interfaces/common/dfx_define.h index 7a41b72c0..5e52d17eb 100644 --- a/interfaces/common/dfx_define.h +++ b/interfaces/common/dfx_define.h @@ -87,6 +87,7 @@ static const char* const PROCESSDUMP_PATH = "/bin/processdump"; #define AT_OPT_NONE __attribute__((optnone)) #define AT_WARN_UNUSED __attribute__((warn_unused_result)) #define AT_UNUSED __attribute__((unused)) +#define AT_FALLTHROUGH __attribute__((fallthrough)) #define MAYBE_UNUSED [[maybe_unused]] #define NO_SANITIZE __attribute__((no_sanitize("address"), no_sanitize("hwaddress"))) diff --git a/interfaces/innerkits/async_stack/BUILD.gn b/interfaces/innerkits/async_stack/BUILD.gn index 6ead9720b..85585a838 100644 --- a/interfaces/innerkits/async_stack/BUILD.gn +++ b/interfaces/innerkits/async_stack/BUILD.gn @@ -44,6 +44,7 @@ if (defined(ohos_lite)) { "$faultloggerd_common_path/dfxlog:dfx_hilog", "$faultloggerd_common_path/dfxutil:dfx_util", "$faultloggerd_interfaces_path/innerkits/backtrace:libbacktrace_local", + "$faultloggerd_interfaces_path/innerkits/signal_handler:dfx_signalhandler", "$faultloggerd_interfaces_path/innerkits/unwinder:libunwinder", ] external_deps = [ diff --git a/interfaces/innerkits/async_stack/async_stack.cpp b/interfaces/innerkits/async_stack/async_stack.cpp index d8ac6b47f..995bca829 100644 --- a/interfaces/innerkits/async_stack/async_stack.cpp +++ b/interfaces/innerkits/async_stack/async_stack.cpp @@ -21,6 +21,7 @@ #include "dfx_frame_formatter.h" #include "dfx_log.h" +#include "dfx_signal_handler.h" #include "fp_backtrace.h" #include "unique_stack_table.h" #include "unwinder.h" @@ -31,14 +32,8 @@ static pthread_key_t g_stackidKey; static bool g_init = false; static OHOS::HiviewDFX::FpBacktrace* g_fpBacktrace = nullptr; -extern "C" void SetAsyncStackCallbackFunc(void* func) __attribute__((weak)); static void InitAsyncStackInner(void) { - if (SetAsyncStackCallbackFunc == nullptr) { - DFXLOGE("failed to init async stack, could not find SetAsyncStackCallbackFunc."); - return; - } - // init unique stack table if (!OHOS::HiviewDFX::UniqueStackTable::Instance()->Init()) { DFXLOGE("failed to init unique stack table?."); @@ -53,7 +48,7 @@ static void InitAsyncStackInner(void) } // set callback for DfxSignalHandler to read stackId - SetAsyncStackCallbackFunc((void*)(&GetStackId)); + DFX_SetAsyncStackCallback(GetStackId); g_fpBacktrace = OHOS::HiviewDFX::FpBacktrace::CreateInstance(); } diff --git a/interfaces/innerkits/signal_handler/dfx_signal_handler.c b/interfaces/innerkits/signal_handler/dfx_signal_handler.c index 85806a8e7..5d58d5090 100644 --- a/interfaces/innerkits/signal_handler/dfx_signal_handler.c +++ b/interfaces/innerkits/signal_handler/dfx_signal_handler.c @@ -74,6 +74,8 @@ #define NSIG 64 #endif +static void DFX_InstallSignalHandler(void); +// preload by libc void __attribute__((constructor)) InitHandler(void) { DFX_InstallSignalHandler(); @@ -107,10 +109,10 @@ static void InitCallbackItems(void) } } -static GetStackIdFunc g_GetStackIdFunc = NULL; -void SetAsyncStackCallbackFunc(void* func) +static GetStackIdFunc g_getStackIdCallback = NULL; +void DFX_SetAsyncStackCallback(GetStackIdFunc func) { - g_GetStackIdFunc = (GetStackIdFunc)func; + g_getStackIdCallback = func; } // caller should set to NULL before exit thread @@ -239,8 +241,8 @@ static bool FillDumpRequest(int signo, siginfo_t *si, void *context) g_appRunningId, sizeof(g_appRunningId)) != EOK) { DFXLOGE("FillDumpRequest appRunningId memcpy fail!"); } - if (!IsDumpSignal(signo) && g_GetStackIdFunc!= NULL) { - g_request.stackId = g_GetStackIdFunc(); + if (!IsDumpSignal(signo) && g_getStackIdCallback != NULL) { + g_request.stackId = g_getStackIdCallback(); DFXLOGI("g_GetStackIdFunc %{private}p.", (void*)g_request.stackId); } GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName)); @@ -255,7 +257,7 @@ static bool FillDumpRequest(int signo, siginfo_t *si, void *context) break; case SIGLEAK_STACK: ret = FillDebugMessageLocked(signo, si); - /* fall-through */ + AT_FALLTHROUGH; default: { ThreadInfoCallBack callback = GetCallbackLocked(); if (callback != NULL) { @@ -365,7 +367,7 @@ static void InstallSigActionHandler(int signo) } } -void DFX_InstallSignalHandler(void) +static void DFX_InstallSignalHandler(void) { if (g_hasInit) { return; diff --git a/interfaces/innerkits/signal_handler/dfx_signalhandler_exception.c b/interfaces/innerkits/signal_handler/dfx_signalhandler_exception.c index 2c7d00be4..47eb93806 100644 --- a/interfaces/innerkits/signal_handler/dfx_signalhandler_exception.c +++ b/interfaces/innerkits/signal_handler/dfx_signalhandler_exception.c @@ -39,8 +39,8 @@ #define LOG_TAG "DfxSignalHandlerException" #endif -static const int TIME_OUT = 2; /* seconds */ -static const char FAULTLOGGERD_SOCKET_NAME[] = "/dev/unix/socket/faultloggerd.server"; +static const int TIME_OUT = 2; /* socket connecet timeout 2 seconds */ +const char * const FAULTLOGGERD_SOCKET_NAME = "/dev/unix/socket/faultloggerd.server"; static int ConnectSocket(const char* path, const int timeout) { diff --git a/interfaces/innerkits/signal_handler/include/dfx_signal_handler.h b/interfaces/innerkits/signal_handler/include/dfx_signal_handler.h index 3bd4f516d..efcce9f16 100644 --- a/interfaces/innerkits/signal_handler/include/dfx_signal_handler.h +++ b/interfaces/innerkits/signal_handler/include/dfx_signal_handler.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Copyright (c) 2021-2025 Huawei Device Co., Ltd. * 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 + * 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, @@ -16,86 +16,114 @@ #define DFX_SIGNAL_HANDLER_H #include -#include -#include -#include +#include #ifdef __cplusplus extern "C" { #endif + /** - * @brief callback function of thread infomation when thread crash + * @brief Callback function for collecting thread information during a crash + * + * This function is invoked when a thread crash occurs, allowing custom + * thread-specific information to be written into the provided buffer. * - * @param buf buffer for writing thread infomation - * @param len length of buffer - * @param ucontext userlevel context -*/ + * @param buf Buffer for writing thread information + * @param len Available buffer length in bytes + * @param ucontext Pointer to user-level context information + */ typedef void(*ThreadInfoCallBack)(char* buf, size_t len, void* ucontext); /** - * @brief set callback function of thread infomation + * @brief Registers a callback for collecting thread information * - * @param func callback function of thread infomation -*/ + * @param func Callback function pointer. Pass NULL to reset to default behavior. + */ void SetThreadInfoCallback(ThreadInfoCallBack func); /** - * @brief install signal handler -*/ -void DFX_InstallSignalHandler(void); - + * @brief Callback type for retrieving thread stack identifier + * + * @return Unique stack identifier (TLS-based) for asynchronous stack tracking + */ typedef uint64_t(*GetStackIdFunc)(void); -void SetAsyncStackCallbackFunc(void* func); +/** + * @brief Registers a callback for retrieving stack identifier + * + * @param func Callback function pointer. Pass NULL to disable stack ID tracking. + */ +void DFX_SetAsyncStackCallback(GetStackIdFunc func); + +/** + * @brief Retrieves the application's running unique identifier + * + * @return Pointer to a null-terminated string representing the unique ID + * Valid until next call to DFX_SetAppRunningUniqueId() + */ const char* DFX_GetAppRunningUniqueId(void); +/** + * @brief Sets the application's running unique identifier + * + * @param appRunningId Pointer to a null-terminated string (max 63 bytes) + * @param len Length of the identifier string (excluding null terminator) + * @return 0 on success, -1 on failure (invalid parameters or memory allocation error) + */ int DFX_SetAppRunningUniqueId(const char* appRunningId, size_t len); +/** + * @brief Types of crash objects for diagnostic information + */ enum CrashObjType : uint8_t { - /* string type */ - OBJ_STRING = 0, - /* 64 byte memory */ - OBJ_MEMORY_64B, - /* 256 byte memory */ - OBJ_MEMORY_256B, - /* 1024 byte memory */ - OBJ_MEMORY_1024B, - /* 2048 byte memory */ - OBJ_MEMORY_2048B, - /* 4096 byte memory */ - OBJ_MEMORY_4096B, + OBJ_STRING = 0, // Null-terminated string (max 1024 bytes) + OBJ_MEMORY_64B, // 64-byte memory block + OBJ_MEMORY_256B, // 256-byte memory block + OBJ_MEMORY_1024B, // 1KB memory block + OBJ_MEMORY_2048B, // 2KB memory block + OBJ_MEMORY_4096B, // 4KB memory block }; + /** - * @brief set crash object which is measurement information of crash + * @brief Attaches diagnostic information to the current crash context + * + * Recommended usage in C++: Prefer RAII-based UniqueCrashObj from + * dfx_unique_crash_obj.h for automatic resource management. * - * @param type type of object, using enum CrashObjType - * @param addr addr of object - * @return return crash Object which set up last time -*/ + * @param type Type of diagnostic data (see CrashObjType) + * @param addr Pointer to the data buffer (must remain valid until crash) + * @return Handle to the previously set crash object (0 if none) + * @note The data pointed to by 'addr' must remain valid until crash occurs + */ uintptr_t DFX_SetCrashObj(uint8_t type, uintptr_t addr); /** - * @brief reset crash object + * @brief Detaches diagnostic information from the current crash context * - * @param crashObj return of DFX_SetCrashObj -*/ + * @param crashObj Handle returned by DFX_SetCrashObj() + */ void DFX_ResetCrashObj(uintptr_t crashObj); +/** + * @brief Configuration options for crash log generation + */ enum CrashLogConfigType : uint8_t { - EXTEND_PRINT_PC_LR = 0, - CUT_OFF_LOG_FILE, - SIMPLIFY_PRINT_MAPS, + EXTEND_PRINT_PC_LR = 0, // extern PC/LR registers in crash logs + CUT_OFF_LOG_FILE, // log file size limits + SIMPLIFY_PRINT_MAPS, // simplified process maps }; + /** - * @brief set crash log config through HiAppEvent + * @brief Configures crash log generation behavior * - * @param type type of config attribute, using enum CrashLogConfigType - * @param value value of config attribute - * @return if succeed return 0, otherwise return -1. The reason for the failure can be found in 'errno' - * @warning this interface is non-thread safety and signal safety -*/ + * @param type Configuration attribute (see CrashLogConfigType) + * @param value Configuration value (semantics depend on type) + * @return 0 on success, -1 on error (check errno for details) + * @warning Non-thread-safe and non-signal-safe. Call early in program initialization. + */ int DFX_SetCrashLogConfig(uint8_t type, uint32_t value); + #ifdef __cplusplus } #endif -#endif +#endif \ No newline at end of file diff --git a/interfaces/innerkits/signal_handler/include/dfx_unique_crash_obj.h b/interfaces/innerkits/signal_handler/include/dfx_unique_crash_obj.h new file mode 100644 index 000000000..688962fc7 --- /dev/null +++ b/interfaces/innerkits/signal_handler/include/dfx_unique_crash_obj.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef DFX_UNIQUE_CRASH_OBJ +#define DFX_UNIQUE_CRASH_OBJ + +#include "dfx_signal_handler.h" + +namespace OHOS { +namespace HiviewDFX { + +/** + * @brief RAII wrapper for managing crash diagnostic objects + * + * Automatically attaches and detaches diagnostic information to the crash context + * using the Resource Acquisition Is Initialization (RAII) pattern. This ensures + * that diagnostic data is properly registered on construction and unregistered + * on destruction, even if exceptions occur. + * + * @warning The diagnostic data buffer pointed to by the constructor argument + * must remain valid for the lifetime of this object. + * + * Example Usage: + * @code + * void ProcessRequest(const std::string& requestId) + * { + * // Attach request ID to crash context for diagnostic purposes + * UniqueCrashObj crashInfo(OBJ_STRING, requestId.c_str()); + * // ... perform operations that might crash ... + * } // crashInfo is automatically detached here + * @endcode + * + * @dependency Add the following to your BUILD.gn: + * @code + * external_deps += [ "faultloggerd:dfx_signalhandler" ] + * @endcode + */ +class UniqueCrashObj final { +public: + /** + * @brief Constructs a UniqueCrashObj and attaches diagnostic data + * + * @param objType Type of diagnostic data (see CrashObjType enum) + * @param objAddr Pointer to the data buffer. Must remain valid until destruction. + */ + explicit UniqueCrashObj(CrashObjType objType, uintptr_t objAddr) + : lastObjAddr_(DFX_SetCrashObj(objType, objAddr)) {} + + /** + * @brief Destructor automatically detaches diagnostic data + */ + ~UniqueCrashObj() + { + DFX_ResetCrashObj(lastObjAddr_); + } + + // Disable copy operations to prevent double detachment + UniqueCrashObj(const UniqueCrashObj&) = delete; + UniqueCrashObj& operator=(const UniqueCrashObj&) = delete; + +private: + uintptr_t lastObjAddr_; // handle to the previously set crash object +}; + +} // namespace HiviewDFX +} // namespace OHOS + +#endif // DFX_UNIQUE_CRASH_OBJ \ No newline at end of file diff --git a/interfaces/innerkits/signal_handler/libdfx_signalhandler.map b/interfaces/innerkits/signal_handler/libdfx_signalhandler.map index ac990f1df..a1693cdd9 100644 --- a/interfaces/innerkits/signal_handler/libdfx_signalhandler.map +++ b/interfaces/innerkits/signal_handler/libdfx_signalhandler.map @@ -2,7 +2,7 @@ global: extern "C" { SetThreadInfoCallback; - SetAsyncStackCallbackFunc; + DFX_SetAsyncStackCallback; DFX_GetAppRunningUniqueId; DFX_SetAppRunningUniqueId; DFX_SetCrashObj; diff --git a/test/unittest/signal_handler/signal_handler_test.cpp b/test/unittest/signal_handler/signal_handler_test.cpp index f80fffb4a..56dfa5522 100644 --- a/test/unittest/signal_handler/signal_handler_test.cpp +++ b/test/unittest/signal_handler/signal_handler_test.cpp @@ -62,10 +62,6 @@ void SignalHandlerTest::SetUp() void SignalHandlerTest::TearDown() {} -extern "C" void SetThreadInfoCallback(ThreadInfoCallBack func); -extern "C" void SetAsyncStackCallbackFunc(void* func); -extern "C" int DFX_SetAppRunningUniqueId(const char* appRunningId, size_t len); -extern "C" int DFX_SetCrashLogConfig(uint8_t type, uint32_t value); static bool CheckCallbackCrashKeyWords(const string& filePath, pid_t pid, int sig) { if (filePath.empty() || pid <= 0) { @@ -606,8 +602,10 @@ HWTEST_F(SignalHandlerTest, SignalHandlerTest013, TestSize.Level2) GTEST_LOG_(INFO) << "SignalHandlerTest013: end."; } -void TestCallbackFunc() -{} +uint64_t TestCallbackFunc() +{ + return 0; +} /** * @tc.name: SignalHandlerTest015 @@ -681,7 +679,7 @@ HWTEST_F(SignalHandlerTest, SignalHandlerTest015, TestSize.Level2) HWTEST_F(SignalHandlerTest, SignalHandlerTest016, TestSize.Level2) { GTEST_LOG_(INFO) << "SignalHandlerTest016: start."; - SetAsyncStackCallbackFunc(reinterpret_cast(TestCallbackFunc)); + DFX_SetAsyncStackCallback(TestCallbackFunc); struct CrashDumpException exception; exception.pid = 1; diff --git a/tools/crasher_cpp/BUILD.gn b/tools/crasher_cpp/BUILD.gn index 63619edc8..db07f52ff 100644 --- a/tools/crasher_cpp/BUILD.gn +++ b/tools/crasher_cpp/BUILD.gn @@ -25,11 +25,15 @@ if (defined(ohos_lite)) { ".", "$faultloggerd_interfaces_path/common", "$faultloggerd_interfaces_path/innerkits/async_stack/include", + "$faultloggerd_interfaces_path/innerkits/signal_handler/include", "$faultloggerd_path/example", "$hilog_lite_include_path", ] sources = [ "dfx_crasher.cpp" ] - deps = [ "$hilog_lite_deps_path" ] + deps = [ + "$hilog_lite_deps_path", + "$faultloggerd_interfaces_path/innerkits/signal_handler:dfx_signalhandler", + ] external_deps = [ "bounds_checking_function:libsec_shared" ] } @@ -77,6 +81,7 @@ if (defined(ohos_lite)) { deps = [ "$faultloggerd_interfaces_path/innerkits/async_stack:libasync_stack", + "$faultloggerd_interfaces_path/innerkits/signal_handler:dfx_signalhandler", "$faultloggerd_interfaces_path/innerkits/unwinder:libunwinder", ] diff --git a/tools/crasher_cpp/dfx_crasher.cpp b/tools/crasher_cpp/dfx_crasher.cpp index 66da81804..f609f16d9 100644 --- a/tools/crasher_cpp/dfx_crasher.cpp +++ b/tools/crasher_cpp/dfx_crasher.cpp @@ -39,6 +39,7 @@ #endif #include "dfx_crash.h" #include "dfx_define.h" +#include "dfx_unique_crash_obj.h" #ifndef is_ohos_lite #include "ffrt_inner.h" #include "uv.h" @@ -163,9 +164,6 @@ constexpr static CrasherCommandLineParam CMDLINE_TABLE_PARAM[] = { #endif }; -extern "C" uintptr_t DFX_SetCrashObj(uint8_t type, uintptr_t addr) __attribute__((weak)); -extern "C" void DFX_ResetCrashObj(uintptr_t crashObj) __attribute__((weak)); - DfxCrasher::DfxCrasher() {} DfxCrasher::~DfxCrasher() {} @@ -532,64 +530,37 @@ NOINLINE int DfxCrasher::PrintFatalMessageInLibc() NOINLINE static void TestGetCrashObjInner() { - uintptr_t val = 0; - if (DFX_SetCrashObj != nullptr) { - uint8_t type = 0; - std::string msg = "test get crashObjectInner."; - val = DFX_SetCrashObj(type, reinterpret_cast(msg.c_str())); - } - if (DFX_ResetCrashObj != nullptr) { - DFX_ResetCrashObj(val); - } + std::string msg = "test get crashObjectInner."; + UniqueCrashObj obj(OBJ_STRING, reinterpret_cast(msg.c_str())); } NOINLINE int DfxCrasher::TestGetCrashObj() { - uintptr_t crashObj = 0; - if (DFX_SetCrashObj != nullptr) { - uint8_t type = 0; - std::string msg = "test get crashObject."; - crashObj = DFX_SetCrashObj(type, reinterpret_cast(msg.c_str())); - } + std::string msg = "test get crashObject."; + UniqueCrashObj obj(OBJ_STRING, reinterpret_cast(msg.c_str())); TestGetCrashObjInner(); raise(SIGSEGV); - if (DFX_ResetCrashObj != nullptr) { - DFX_ResetCrashObj(crashObj); - } return 0; } NOINLINE static void TestGetCrashObjMemoryInner() { - uint8_t type = 1; - uintptr_t val = 0; constexpr size_t bufSize = 4096; uintptr_t memory[bufSize] = {2}; - if (DFX_SetCrashObj != nullptr) { - val = DFX_SetCrashObj(type, reinterpret_cast(memory)); - } - if (DFX_ResetCrashObj != nullptr) { - DFX_ResetCrashObj(val); - } + UniqueCrashObj obj(OBJ_MEMORY_64B, reinterpret_cast(memory)); } NOINLINE int DfxCrasher::TestGetCrashObjMemory() { - uint8_t type = 5; - uintptr_t crashObj = 0; constexpr size_t bufSize = 4096; uintptr_t memory[bufSize]; for (size_t i = 0; i < bufSize; i++) { memory[i] = i; } - if (DFX_SetCrashObj != nullptr) { - crashObj = DFX_SetCrashObj(type, reinterpret_cast(memory)); - } + UniqueCrashObj obj(OBJ_MEMORY_4096B, reinterpret_cast(memory)); + TestGetCrashObjMemoryInner(); raise(SIGSEGV); - if (DFX_ResetCrashObj != nullptr) { - DFX_ResetCrashObj(crashObj); - } return 0; } -- Gitee