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