From 103e2853858af67cb672f0eff784afee6f652bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E9=87=91=E6=88=90?= Date: Tue, 24 Dec 2024 18:37:00 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20DFX=20=E4=B8=8E=20llvm=20s?= =?UTF-8?q?anitizer=20=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD=E4=B8=8D?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E7=9A=84=E9=97=AE=E9=A2=98=20ohos=5Fdfx=5Flo?= =?UTF-8?q?g=20=E5=88=86=E9=85=8D=E4=B8=80=E4=B8=AA=E7=BC=93=E5=86=B2?= =?UTF-8?q?=E5=8C=BA=EF=BC=8C=E7=BC=93=E5=AD=98=20llvm=20=E6=97=A5?= =?UTF-8?q?=E5=BF=97=EF=BC=8C=E9=81=87=E5=88=B0=E7=BB=93=E6=9D=9F=E7=AC=A6?= =?UTF-8?q?=E5=86=8D=E8=B0=83=20dlopen=20=E4=BC=A0=E7=BB=99=20dfx=20?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=20issue:=20https://gitee.com/openharmony/thi?= =?UTF-8?q?rd=5Fparty=5Fmusl/issues/IBDBGS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 胡金成 Change-Id: Id80b13f0eb53a79492dedd31c845022a4758acf6 --- .../src/functionalext/ohos_dfx_log/BUILD.gn | 12 ++ .../ohos_dfx_log/ohos_dfx_log.cpp | 181 ++++++++++++++++++ .../functionalext/test_src_functionalext.gni | 1 + src/internal/linux/musl_log.c | 109 +++++++++-- 4 files changed, 282 insertions(+), 21 deletions(-) create mode 100644 libc-test/src/functionalext/ohos_dfx_log/BUILD.gn create mode 100644 libc-test/src/functionalext/ohos_dfx_log/ohos_dfx_log.cpp diff --git a/libc-test/src/functionalext/ohos_dfx_log/BUILD.gn b/libc-test/src/functionalext/ohos_dfx_log/BUILD.gn new file mode 100644 index 000000000..bb9b86b24 --- /dev/null +++ b/libc-test/src/functionalext/ohos_dfx_log/BUILD.gn @@ -0,0 +1,12 @@ +import("../../../../musl_template.gni") +import("../../../test_template.gni") + +ohos_executable("ohos_dfx_log") { + testonly = true + subsystem_name = "musl" + part_name = "libc-test" + + sources = [ "ohos_dfx_log.cpp" ] + include_dirs = [ "//third_party/musl/libc-test/src/common" ] + configs = [ "//third_party/musl/libc-test/src/common:config_runtest" ] +} diff --git a/libc-test/src/functionalext/ohos_dfx_log/ohos_dfx_log.cpp b/libc-test/src/functionalext/ohos_dfx_log/ohos_dfx_log.cpp new file mode 100644 index 000000000..47fc358b1 --- /dev/null +++ b/libc-test/src/functionalext/ohos_dfx_log/ohos_dfx_log.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved. + * 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. + */ +extern "C" { + #include "../../common/test.h" +} +#include +#include +#include +#include +#include + +constexpr int MAX_BUFFER_SIZE = 128; +constexpr const char *FAULTLOG_DIR = "/data/log/faultlog/faultlogger/"; +constexpr const char *LOG_TAG = "ohos_dfx_log"; + +extern "C" __attribute__((weak)) int ohos_dfx_log(const char *s); + +static void ClearDfxLogs() +{ + DIR *dir; + struct dirent *ptr; + dir = opendir(FAULTLOG_DIR); + while ((ptr = readdir(dir)) != NULL) { + if (strstr(ptr->d_name, LOG_TAG) != NULL) { + char tmp[MAX_BUFFER_SIZE]; + snprintf(tmp, MAX_BUFFER_SIZE, "%s/%s", FAULTLOG_DIR, ptr->d_name); + remove(tmp); + } + } + closedir(dir); +} + +static void CheckLogContent(char *file, const char *content) +{ + FILE *fp = fopen(file, "r"); + if (!fp) { + return; + } + if (fseek(fp, 0, SEEK_END) == -1) { + return; + } + int size = ftell(fp); + if (size <= 0) { + fclose(fp); + t_error("FAIL %s size is <=0!\n", file); + } + + std::string buffer; + buffer.resize(size); + + if (fseek(fp, 0, SEEK_SET) == -1) { + fclose(fp); + return; + } + int rsize = fread(&buffer[0], 1, size, fp); + if (rsize == 0) { + fclose(fp); + return; + } + + if (buffer.find(content) != std::string::npos) { + printf("[ohos_dfx_log] check pass:\n%s\n", content); + } else { + t_error("[ohos_dfx_log] failed:\n%s\n", content); + } + + fclose(fp); +} + +static void CheckLog(const char *content) +{ + sleep(1); + DIR *faultlogDir = opendir(FAULTLOG_DIR); + struct dirent *ptr; + while ((ptr = readdir(faultlogDir)) != NULL) { + if (strstr(ptr->d_name, LOG_TAG) != NULL) { + char tmp[MAX_BUFFER_SIZE]; + snprintf(tmp, MAX_BUFFER_SIZE, "%s/%s", FAULTLOG_DIR, ptr->d_name); + CheckLogContent(tmp, content); + break; + } + } + closedir(faultlogDir); +} + +void TestAsanLog() +{ + ClearDfxLogs(); + if (&ohos_dfx_log) { + ohos_dfx_log("[ohos_dfx_log] output something to the log path.\n"); + ohos_dfx_log("End Asan report"); + CheckLog("[ohos_dfx_log] output something to the log path.\nEnd Asan report"); + } else { + t_error("[ohos_dfx_log] cannot find ohos_dfx_log"); + } +} + +void TestHWAsanLog() +{ + ClearDfxLogs(); + if (&ohos_dfx_log) { + ohos_dfx_log("[ohos_dfx_log] output something to the log path.\n"); + ohos_dfx_log("End Hwasan report"); + CheckLog("[ohos_dfx_log] output something to the log path.\nEnd Hwasan report"); + } else { + t_error("[ohos_dfx_log] cannot find ohos_dfx_log"); + } +} + +void TestTsanLog() +{ + ClearDfxLogs(); + if (&ohos_dfx_log) { + ohos_dfx_log("[ohos_dfx_log] output something to the log path.\n"); + ohos_dfx_log("End Tsan report"); + CheckLog("[ohos_dfx_log] output something to the log path.\nEnd Tsan report"); + } else { + t_error("[ohos_dfx_log] cannot find ohos_dfx_log"); + } +} + +void TestUbsanLog() +{ + ClearDfxLogs(); + if (&ohos_dfx_log) { + ohos_dfx_log("[ohos_dfx_log] output something to the log path.\n"); + ohos_dfx_log("End Ubsan report"); + CheckLog("[ohos_dfx_log] output something to the log path.\nEnd Ubsan report"); + } else { + t_error("[ohos_dfx_log] cannot find ohos_dfx_log"); + } +} + +void TestCfiLog() +{ + ClearDfxLogs(); + if (&ohos_dfx_log) { + ohos_dfx_log("[ohos_dfx_log] output something to the log path.\n"); + ohos_dfx_log("End CFI report"); + CheckLog("[ohos_dfx_log] output something to the log path.\nEnd CFI report"); + } else { + t_error("[ohos_dfx_log] cannot find ohos_dfx_log"); + } +} + +void TestBufferExpand() +{ + ClearDfxLogs(); + if (&ohos_dfx_log) { + for (int i = 0; i < 5000; ++i) { + ohos_dfx_log("ohos_dfx_log output something to the log path ohos_dfx_log output something to the log path.\n"); + } + ohos_dfx_log("End Asan report"); + CheckLog("End Asan report"); + } else { + t_error("[ohos_dfx_log] cannot find ohos_dfx_log"); + } +} + +int main() +{ + TestAsanLog(); + TestHWAsanLog(); + TestTsanLog(); + TestUbsanLog(); + TestCfiLog(); + TestBufferExpand(); + return t_status; +} \ No newline at end of file diff --git a/libc-test/src/functionalext/test_src_functionalext.gni b/libc-test/src/functionalext/test_src_functionalext.gni index e51cf505d..fb1c5f26a 100644 --- a/libc-test/src/functionalext/test_src_functionalext.gni +++ b/libc-test/src/functionalext/test_src_functionalext.gni @@ -38,4 +38,5 @@ functionalext_list = [ "ldso_same_name_symbol:ldso_same_symbol_name_with_different_version", "dl_different_hash:dl_different_hash", "hilog:hilog_level", + "ohos_dfx_log:ohos_dfx_log", ] diff --git a/src/internal/linux/musl_log.c b/src/internal/linux/musl_log.c index 5ec3d3ca3..abdfa249a 100644 --- a/src/internal/linux/musl_log.c +++ b/src/internal/linux/musl_log.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Huawei Device Co., Ltd. + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved. * 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 @@ -13,17 +13,19 @@ * limitations under the License. */ -#include +#define _GNU_SOURCE +#include #include #include #include #include #include #include +#include #include "musl_log.h" -#define PATH_MAX 256 +#define DEFAULT_STRING_SIZE 409600 #define DFX_LOG_LIB "libasan_logger.z.so" #define DFX_LOG_INTERFACE "WriteGwpAsanLog" static void (*g_dfxLogPtr)(char*, size_t); @@ -31,42 +33,107 @@ static void* g_dfxLibHandler = NULL; static pthread_mutex_t g_muslLogMutex = PTHREAD_MUTEX_INITIALIZER; extern bool g_dl_inited; // flag indicates musl ldso initialization completed extern bool g_global_destroyed; // flag indicates global variables have been destroyed +char *g_buffer = NULL; // an area of memory used to cache each line of sanitizer logs +size_t g_offset = 0; // the size of logs that have been cached to g_buffer +size_t g_end = DEFAULT_STRING_SIZE; // the size of g_buffer -int ohos_dfx_log(const char *str) +static void buffer_clean_up(const char *str) { - if (g_global_destroyed) { - return 0; + int unmapRes = munmap(g_buffer, g_end); + if (unmapRes == -1) { + MUSL_LOGE("[ohos_dfx_log] munmap g_buffer failed: %{public}d %{public}s:\n %{public}s\n", + errno, strerror(errno), str); } + g_buffer = NULL; + g_offset = 0; + g_end = DEFAULT_STRING_SIZE; +} + +/* + * This function is not async-signal-safe + * Don't use it in signal handler or in child process that is forked from any other process + * Don't use it during initialization + * Don't use it before execve +*/ +static void write_to_dfx(const char *str) +{ if (g_dfxLogPtr != NULL) { - g_dfxLogPtr(str, strlen(str)); - return 0; + g_dfxLogPtr(g_buffer, g_offset); + return; } + if (!g_dl_inited) { - return 0; + return; } - pthread_mutex_lock(&g_muslLogMutex); - if (g_dfxLogPtr != NULL) { - g_dfxLogPtr(str, strlen(str)); - pthread_mutex_unlock(&g_muslLogMutex); - return 0; - } if (g_dfxLibHandler == NULL) { g_dfxLibHandler = dlopen(DFX_LOG_LIB, RTLD_LAZY); if (g_dfxLibHandler == NULL) { - MUSL_LOGE("[musl_log] dlopen %{public}s failed!\n", DFX_LOG_LIB); - pthread_mutex_unlock(&g_muslLogMutex); - return 0; + MUSL_LOGE("[ohos_dfx_log] dlopen %{public}s failed!\n", DFX_LOG_LIB); + return; } } if (g_dfxLogPtr == NULL) { *(void **)(&g_dfxLogPtr) = dlsym(g_dfxLibHandler, DFX_LOG_INTERFACE); if (g_dfxLogPtr != NULL) { - g_dfxLogPtr(str, strlen(str)); + g_dfxLogPtr(g_buffer, g_offset); } else { - MUSL_LOGE("[musl_log] dlsym %{public}s, failed!\n", DFX_LOG_INTERFACE); + MUSL_LOGE("[ohos_dfx_log] dlsym %{public}s, failed!\n", DFX_LOG_INTERFACE); } } +} + +/* + * This function is exclusively for LLVM Sanitizers to flush logs to disk + * Don't use it for other purposes + * This function is not async-signal-safe + * Don't use it in signal handler or in child process that is forked from any other process + * Don't use it during initialization + * Don't use it before execve +*/ +int ohos_dfx_log(const char *str) +{ + if (g_global_destroyed) { + return 0; + } + + pthread_mutex_lock(&g_muslLogMutex); + if (g_buffer == NULL) { + g_buffer = mmap(NULL, DEFAULT_STRING_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (g_buffer == MAP_FAILED) { + MUSL_LOGE("[ohos_dfx_log] mmap g_buffer failed: %{public}d %{public}s:\n %{public}s\n", + errno, strerror(errno), str); + pthread_mutex_unlock(&g_muslLogMutex); + return 0; + } + } + + size_t new_end = g_offset + strlen(str); + if (new_end > g_end) { + char *new_buffer = mremap(g_buffer, g_end, g_end * 2, MREMAP_MAYMOVE); + if (new_buffer == MAP_FAILED) { + MUSL_LOGE("[ohos_dfx_log] mremap new_buffer failed: %{public}d %{public}s:\n %{public}s\n", + errno, strerror(errno), str); + pthread_mutex_unlock(&g_muslLogMutex); + return 0; + } + g_end = g_end * 2; + g_buffer = new_buffer; + MUSL_LOGE("[ohos_dfx_log] g_end expand to %{public}d\n", g_end); + } + + strcpy(g_buffer + g_offset, str); + g_offset += strlen(str); + + if (!(strstr(str, "End Hwasan report") || strstr(str, "End Asan report") || + strstr(str, "End Tsan report") || strstr(str, "End Ubsan report") || + strstr(str, "End CFI report"))) { + pthread_mutex_unlock(&g_muslLogMutex); + return 0; + } + + write_to_dfx(str); + buffer_clean_up(str); pthread_mutex_unlock(&g_muslLogMutex); return 0; @@ -80,4 +147,4 @@ int musl_log(const char *fmt, ...) ret = HiLogAdapterPrintArgs(MUSL_LOG_TYPE, LOG_INFO, MUSL_LOG_DOMAIN, MUSL_LOG_TAG, fmt, ap); va_end(ap); return ret; -} +} \ No newline at end of file -- Gitee