• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define _GNU_SOURCE
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <dlfcn.h>
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <pthread.h>
24 #include <sys/mman.h>
25 
26 #include "musl_log.h"
27 
28 #define DEFAULT_STRING_SIZE 409600
29 #define DFX_LOG_LIB "libasan_logger.z.so"
30 #define DFX_LOG_INTERFACE "WriteSanitizerLog"
31 static void (*g_dfxLogPtr)(char*, size_t, char*);
32 static void* g_dfxLibHandler = NULL;
33 static pthread_mutex_t g_muslLogMutex = PTHREAD_MUTEX_INITIALIZER;
34 extern bool g_dl_inited; // flag indicates musl ldso initialization completed
35 extern bool g_global_destroyed; // flag indicates global variables have been destroyed
36 char *g_buffer = NULL; // an area of memory used to cache each line of sanitizer logs
37 size_t g_offset = 0; // the size of logs that have been cached to g_buffer
38 size_t g_end = DEFAULT_STRING_SIZE; // the size of g_buffer
39 
buffer_clean_up(const char * str)40 static void buffer_clean_up(const char *str)
41 {
42     if (g_buffer != NULL) {
43         int unmapRes = munmap(g_buffer, g_end);
44         if (unmapRes == -1) {
45             MUSL_LOGW("[ohos_dfx_log] munmap g_buffer failed: %{public}d %{public}s:\n %{public}s\n",
46                 errno, strerror(errno), str);
47         }
48     }
49     g_buffer = NULL;
50     g_offset = 0;
51     g_end = DEFAULT_STRING_SIZE;
52 }
53 
load_asan_logger()54 bool load_asan_logger()
55 {
56     if (g_dfxLibHandler == NULL) {
57         g_dfxLibHandler = dlopen(DFX_LOG_LIB, RTLD_LAZY);
58         if (g_dfxLibHandler == NULL) {
59             MUSL_LOGW("[ohos_dfx_log] dlopen %{public}s failed!\n", DFX_LOG_LIB);
60             return false;
61         }
62     }
63     if (g_dfxLogPtr == NULL) {
64         *(void **)(&g_dfxLogPtr) = dlsym(g_dfxLibHandler, DFX_LOG_INTERFACE);
65         if (g_dfxLogPtr == NULL) {
66             MUSL_LOGW("[ohos_dfx_log] dlsym %{public}s, failed!\n", DFX_LOG_INTERFACE);
67             return false;
68         }
69     }
70     return true;
71 }
72 
73 /*
74  * This function is not async-signal-safe
75  * Don't use it in signal handler or in child process that is forked from any other process
76  * Don't use it during initialization
77  * Don't use it before execve
78 */
write_to_dfx(const char * str,const char * path)79 static void write_to_dfx(const char *str, const char *path)
80 {
81     if (g_dfxLogPtr != NULL) {
82         g_dfxLogPtr(g_buffer, g_offset, (char *)path);
83         return;
84     }
85 
86     if (!g_dl_inited) {
87         return;
88     }
89 
90     if (!load_asan_logger()) {
91         return;
92     }
93     g_dfxLogPtr(g_buffer, g_offset, (char *)path);
94 }
95 
96 /*
97  * This function is exclusively for LLVM Sanitizers to flush logs to disk
98  * Don't use it for other purposes
99  * This function is not async-signal-safe
100  * Don't use it in signal handler or in child process that is forked from any other process
101  * Don't use it during initialization
102  * Don't use it before execve
103 */
ohos_dfx_log(const char * str,const char * path)104 int ohos_dfx_log(const char *str, const char *path)
105 {
106     if (g_global_destroyed || str == NULL) {
107         return 0;
108     }
109 
110     pthread_mutex_lock(&g_muslLogMutex);
111     if (g_buffer == NULL) {
112         g_buffer = mmap(NULL, DEFAULT_STRING_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
113         if (g_buffer == MAP_FAILED) {
114             MUSL_LOGW("[ohos_dfx_log] mmap g_buffer failed: %{public}d %{public}s:\n %{public}s\n",
115                 errno, strerror(errno), str);
116             pthread_mutex_unlock(&g_muslLogMutex);
117             return 0;
118         }
119     }
120 
121     size_t str_len = strlen(str);
122     size_t new_end = g_offset + str_len + 1;
123     if (new_end > g_end) {
124         char *new_buffer = mremap(g_buffer, g_end, g_end * 2, MREMAP_MAYMOVE);
125         if (new_buffer == MAP_FAILED) {
126             MUSL_LOGW("[ohos_dfx_log] mremap new_buffer failed: %{public}d %{public}s:\n %{public}s\n",
127                 errno, strerror(errno), str);
128             pthread_mutex_unlock(&g_muslLogMutex);
129             return 0;
130         }
131         g_end = g_end * 2;
132         g_buffer = new_buffer;
133         MUSL_LOGW("[ohos_dfx_log] g_end expand to %{public}lu\n", g_end);
134     }
135 
136     strcpy(g_buffer + g_offset, str);
137     g_offset += str_len;
138 
139     if (!(strstr(str, "End Hwasan report") || strstr(str, "End Asan report") ||
140     strstr(str, "End Tsan report") || strstr(str, "End Ubsan report") ||
141     strstr(str, "End CFI report"))) {
142         pthread_mutex_unlock(&g_muslLogMutex);
143         return 0;
144     }
145 
146     write_to_dfx(str, path);
147     buffer_clean_up(str);
148     pthread_mutex_unlock(&g_muslLogMutex);
149 
150     return 0;
151 }
152 
musl_log(const char * fmt,...)153 int musl_log(const char *fmt, ...)
154 {
155     int ret;
156     va_list ap;
157     va_start(ap, fmt);
158     ret = HiLogAdapterPrintArgs(MUSL_LOG_TYPE, LOG_INFO, MUSL_LOG_DOMAIN, MUSL_LOG_TAG, fmt, ap);
159     va_end(ap);
160     return ret;
161 }