• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &currentAddr)) {
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