1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
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 #include "dfx_util.h"
17
18 #if defined(is_mingw) && is_mingw
19 #include <memoryapi.h>
20 #include <windows.h>
21 #endif
22 #ifndef is_host
23 #include <cctype>
24 #include <climits>
25 #include <cstdio>
26 #include <cstdlib>
27 #include <cstring>
28 #include <ctime>
29 #include <securec.h>
30 #include <sys/types.h>
31 #include <sys/time.h>
32 #include <fcntl.h>
33 #include <pthread.h>
34 #include <unistd.h>
35 #include <dirent.h>
36 #endif
37 #include <sys/stat.h>
38
39 #include "dfx_log.h"
40 #if !defined(is_ohos_lite) && !defined(DFX_UTIL_STATIC)
41 #include "parameters.h"
42 #endif // !is_ohos_lite
43
44 #ifdef LOG_DOMAIN
45 #undef LOG_DOMAIN
46 #define LOG_DOMAIN 0xD002D11
47 #endif
48
49 #ifdef LOG_TAG
50 #undef LOG_TAG
51 #define LOG_TAG "DfxUtil"
52 #endif
53
54 namespace OHOS {
55 namespace HiviewDFX {
56 #ifndef is_host
TrimAndDupStr(const std::string & source,std::string & str)57 bool TrimAndDupStr(const std::string &source, std::string &str)
58 {
59 if (source.empty()) {
60 return false;
61 }
62
63 const char *begin = source.data();
64 const char *end = begin + source.size();
65 if (begin == end) {
66 DFXLOGE("Source is empty");
67 return false;
68 }
69
70 while ((begin < end) && isspace(*begin)) {
71 begin++;
72 }
73
74 while ((begin < end) && isspace(*(end - 1))) {
75 end--;
76 }
77
78 if (begin == end) {
79 return false;
80 }
81
82 uint32_t maxStrLen = NAME_BUF_LEN;
83 uint32_t offset = static_cast<uint32_t>(end - begin);
84 if (maxStrLen > offset) {
85 maxStrLen = offset;
86 }
87
88 str.assign(begin, maxStrLen);
89 return true;
90 }
91
GetTimeMilliSeconds(void)92 uint64_t GetTimeMilliSeconds(void)
93 {
94 struct timespec ts;
95 (void)clock_gettime(CLOCK_REALTIME, &ts);
96 return ((uint64_t)ts.tv_sec * NUMBER_ONE_THOUSAND) + // 1000 : second to millisecond convert ratio
97 (((uint64_t)ts.tv_nsec) / NUMBER_ONE_MILLION); // 1000000 : nanosecond to millisecond convert ratio
98 }
99
GetAbsTimeMilliSeconds(void)100 uint64_t GetAbsTimeMilliSeconds(void)
101 {
102 struct timespec ts;
103 (void)clock_gettime(CLOCK_MONOTONIC, &ts);
104 return (static_cast<uint64_t>(ts.tv_sec) * NUMBER_ONE_THOUSAND) +
105 (static_cast<uint64_t>(ts.tv_nsec) / NUMBER_ONE_MILLION);
106 }
107
GetCurrentTimeStr(uint64_t current)108 std::string GetCurrentTimeStr(uint64_t current)
109 {
110 time_t now = time(nullptr);
111 uint64_t millsecond = 0;
112 const uint64_t ratio = NUMBER_ONE_THOUSAND;
113 if (current > static_cast<uint64_t>(now)) {
114 millsecond = current % ratio;
115 now = static_cast<time_t>(current / ratio);
116 }
117
118 auto tm = std::localtime(&now);
119 char seconds[128] = {0}; // 128 : time buffer size
120 if (tm == nullptr || strftime(seconds, sizeof(seconds) - 1, "%Y-%m-%d %H:%M:%S", tm) == 0) {
121 return "invalid timestamp\n";
122 }
123
124 char millBuf[256] = {0}; // 256 : milliseconds buffer size
125 int ret = snprintf_s(millBuf, sizeof(millBuf), sizeof(millBuf) - 1,
126 "%s.%03u\n", seconds, millsecond);
127 if (ret <= 0) {
128 return "invalid timestamp\n";
129 }
130 return std::string(millBuf, strlen(millBuf));
131 }
132
ReadDirFiles(const std::string & path,std::vector<std::string> & files)133 bool ReadDirFiles(const std::string& path, std::vector<std::string>& files)
134 {
135 DIR *dir = opendir(path.c_str());
136 if (dir == nullptr) {
137 return false;
138 }
139
140 struct dirent *ent;
141 while ((ent = readdir(dir)) != nullptr) {
142 // current dir OR parent dir
143 if ((strcmp(ent->d_name, ".") == 0) || (strcmp(ent->d_name, "..") == 0)) {
144 continue;
145 }
146 files.emplace_back(std::string(ent->d_name));
147 }
148 (void)closedir(dir);
149 return (files.size() > 0);
150 }
151
VerifyFilePath(const std::string & filePath,const std::vector<const std::string> & validPaths)152 bool VerifyFilePath(const std::string& filePath, const std::vector<const std::string>& validPaths)
153 {
154 if (validPaths.size() == 0) {
155 return true;
156 }
157
158 for (auto validPath : validPaths) {
159 if (filePath.find(validPath) == 0) {
160 return true;
161 }
162 }
163 return false;
164 }
165
ParseSiValue(siginfo_t & si,uint64_t & endTime,int & tid)166 void ParseSiValue(siginfo_t& si, uint64_t& endTime, int& tid)
167 {
168 const int flagOffset = 63;
169 if ((reinterpret_cast<uint64_t>(si.si_value.sival_ptr) & (1ULL << flagOffset)) != 0) {
170 endTime = reinterpret_cast<uint64_t>(si.si_value.sival_ptr) & (~(1ULL << flagOffset));
171 tid = 0;
172 } else {
173 endTime = 0;
174 tid = si.si_value.sival_int;
175 }
176 }
177 #endif
178
GetFileSize(const int & fd)179 off_t GetFileSize(const int& fd)
180 {
181 off_t fileSize = 0;
182 if (fd >= 0) {
183 struct stat fileStat;
184 if (fstat(fd, &fileStat) == 0) {
185 fileSize = fileStat.st_size;
186 }
187 }
188 return fileSize;
189 }
190
ReadFdToString(int fd,std::string & content)191 bool ReadFdToString(int fd, std::string& content)
192 {
193 content.clear();
194 struct stat sb;
195 if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
196 content.reserve(sb.st_size);
197 }
198
199 char buf[BUFSIZ] __attribute__((__uninitialized__));
200 ssize_t n;
201 while ((n = OHOS_TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
202 content.append(buf, n);
203 }
204 return (n == 0);
205 }
206
CloseFd(int & fd)207 void CloseFd(int &fd)
208 {
209 if (fd > 0) {
210 close(fd);
211 fd = -1;
212 }
213 }
214
StripPac(uintptr_t inAddr,uintptr_t pacMask)215 uintptr_t StripPac(uintptr_t inAddr, uintptr_t pacMask)
216 {
217 uintptr_t outAddr = inAddr;
218 #if defined(__aarch64__)
219 if (outAddr != 0) {
220 if (pacMask != 0) {
221 outAddr &= ~pacMask;
222 } else {
223 register uint64_t x30 __asm("x30") = inAddr;
224 asm("hint 0x7" : "+r"(x30));
225 outAddr = x30;
226 }
227 }
228 #endif
229 return outAddr;
230 }
231
IsBetaVersion()232 bool IsBetaVersion()
233 {
234 #if !defined(is_ohos_lite) && !defined(DFX_UTIL_STATIC)
235 const char *const logsystemVersionType = "const.logsystem.versiontype";
236 static bool isBetaVersion = OHOS::system::GetParameter(logsystemVersionType, "") == "beta";
237 return isBetaVersion;
238 #else
239 return false;
240 #endif
241 }
242
IsDeveloperMode()243 bool IsDeveloperMode()
244 {
245 #if !defined(is_ohos_lite) && !defined(DFX_UTIL_STATIC)
246 const char *const developerMode = "const.security.developermode.state";
247 static bool isDeveloperMode = OHOS::system::GetParameter(developerMode, "") == "true";
248 return isDeveloperMode;
249 #else
250 return false;
251 #endif
252 }
253 } // namespace HiviewDFX
254 } // namespace OHOS
255
256 // this will also used for libunwinder head (out of namespace)
257 #if defined(is_mingw) && is_mingw
GetLastErrorString()258 std::string GetLastErrorString()
259 {
260 LPVOID lpMsgBuf;
261 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
262 FORMAT_MESSAGE_IGNORE_INSERTS,
263 NULL, GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, NULL);
264 std::string error((LPTSTR)lpMsgBuf);
265 LocalFree(lpMsgBuf);
266 return error;
267 }
268
mmap(void * addr,size_t length,int prot,int flags,int fd,size_t offset)269 void *mmap(void *addr, size_t length, int prot, int flags, int fd, size_t offset)
270 {
271 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
272 if (FileHandle == INVALID_HANDLE_VALUE) {
273 return MMAP_FAILED;
274 }
275
276 DFXLOGD("fd is %{public}d", fd);
277
278 HANDLE FileMappingHandle = ::CreateFileMappingW(FileHandle, 0, PAGE_READONLY, 0, 0, 0);
279 if (FileMappingHandle == nullptr) {
280 DFXLOGE("CreateFileMappingW %{public}zu Failed with %{public}ld:%{public}s",
281 length, GetLastError(), GetLastErrorString().c_str());
282 return MMAP_FAILED;
283 }
284
285 void *mapAddr = ::MapViewOfFile(FileMappingHandle, FILE_MAP_READ, 0, 0, 0);
286 if (mapAddr == nullptr) {
287 DFXLOGE("MapViewOfFile %{public}zu Failed with %{public}ld:%{public}s",
288 length, GetLastError(), GetLastErrorString().c_str());
289 return MMAP_FAILED;
290 }
291
292 // Close all the handles except for the view. It will keep the other handles
293 // alive.
294 ::CloseHandle(FileMappingHandle);
295 return mapAddr;
296 }
297
munmap(void * addr,size_t)298 int munmap(void *addr, size_t)
299 {
300 /*
301 On success, munmap() returns 0. On failure, it returns -1, and
302 errno is set to indicate the error (probably to EINVAL).
303
304 UnmapViewOfFile function (memoryapi.h)
305
306 If the function succeeds, the return value is nonzero.
307 If the function fails, the return value is zero. To get extended error information, call
308 GetLastError.
309 */
310 return !UnmapViewOfFile(addr);
311 }
312 #endif
313