• 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     int unmapRes = munmap(g_buffer, g_end);
43     if (unmapRes == -1) {
44         MUSL_LOGE("[ohos_dfx_log] munmap g_buffer failed: %{public}d %{public}s:\n %{public}s\n",
45             errno, strerror(errno), str);
46     }
47     g_buffer = NULL;
48     g_offset = 0;
49     g_end = DEFAULT_STRING_SIZE;
50 }
51 
load_asan_logger()52 bool load_asan_logger()
53 {
54     if (g_dfxLibHandler == NULL) {
55         g_dfxLibHandler = dlopen(DFX_LOG_LIB, RTLD_LAZY);
56         if (g_dfxLibHandler == NULL) {
57             MUSL_LOGE("[ohos_dfx_log] dlopen %{public}s failed!\n", DFX_LOG_LIB);
58             return false;
59         }
60     }
61     if (g_dfxLogPtr == NULL) {
62         *(void **)(&g_dfxLogPtr) = dlsym(g_dfxLibHandler, DFX_LOG_INTERFACE);
63         if (g_dfxLogPtr == NULL) {
64             MUSL_LOGE("[ohos_dfx_log] dlsym %{public}s, failed!\n", DFX_LOG_INTERFACE);
65             return false;
66         }
67     }
68     return true;
69 }
70 
71 /*
72  * This function is not async-signal-safe
73  * Don't use it in signal handler or in child process that is forked from any other process
74  * Don't use it during initialization
75  * Don't use it before execve
76 */
write_to_dfx(const char * str,const char * path)77 static void write_to_dfx(const char *str, const char *path)
78 {
79     if (g_dfxLogPtr != NULL) {
80         g_dfxLogPtr(g_buffer, g_offset, (char *)path);
81         return;
82     }
83 
84     if (!g_dl_inited) {
85         return;
86     }
87 
88     if (!load_asan_logger()) {
89         return;
90     }
91     g_dfxLogPtr(g_buffer, g_offset, (char *)path);
92 }
93 
94 /*
95  * This function is exclusively for LLVM Sanitizers to flush logs to disk
96  * Don't use it for other purposes
97  * This function is not async-signal-safe
98  * Don't use it in signal handler or in child process that is forked from any other process
99  * Don't use it during initialization
100  * Don't use it before execve
101 */
ohos_dfx_log(const char * str,const char * path)102 int ohos_dfx_log(const char *str, const char *path)
103 {
104     if (g_global_destroyed) {
105         return 0;
106     }
107 
108     pthread_mutex_lock(&g_muslLogMutex);
109     if (g_buffer == NULL) {
110         g_buffer = mmap(NULL, DEFAULT_STRING_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
111         if (g_buffer == MAP_FAILED) {
112             MUSL_LOGE("[ohos_dfx_log] mmap g_buffer failed: %{public}d %{public}s:\n %{public}s\n",
113                 errno, strerror(errno), str);
114             pthread_mutex_unlock(&g_muslLogMutex);
115             return 0;
116         }
117     }
118 
119     size_t new_end = g_offset + strlen(str);
120     if (new_end > g_end) {
121         char *new_buffer = mremap(g_buffer, g_end, g_end * 2, MREMAP_MAYMOVE);
122         if (new_buffer == MAP_FAILED) {
123             MUSL_LOGE("[ohos_dfx_log] mremap new_buffer failed: %{public}d %{public}s:\n %{public}s\n",
124                 errno, strerror(errno), str);
125             pthread_mutex_unlock(&g_muslLogMutex);
126             return 0;
127         }
128         g_end = g_end * 2;
129         g_buffer = new_buffer;
130         MUSL_LOGE("[ohos_dfx_log] g_end expand to %{public}lu\n", g_end);
131     }
132 
133     strcpy(g_buffer + g_offset, str);
134     g_offset += strlen(str);
135 
136     if (!(strstr(str, "End Hwasan report") || strstr(str, "End Asan report") ||
137     strstr(str, "End Tsan report") || strstr(str, "End Ubsan report") ||
138     strstr(str, "End CFI report"))) {
139         pthread_mutex_unlock(&g_muslLogMutex);
140         return 0;
141     }
142 
143     write_to_dfx(str, path);
144     buffer_clean_up(str);
145     pthread_mutex_unlock(&g_muslLogMutex);
146 
147     return 0;
148 }
149 
musl_log(const char * fmt,...)150 int musl_log(const char *fmt, ...)
151 {
152     int ret;
153     va_list ap;
154     va_start(ap, fmt);
155     ret = HiLogAdapterPrintArgs(MUSL_LOG_TYPE, LOG_INFO, MUSL_LOG_DOMAIN, MUSL_LOG_TAG, fmt, ap);
156     va_end(ap);
157     return ret;
158 }