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 
41 #ifdef LOG_DOMAIN
42 #undef LOG_DOMAIN
43 #define LOG_DOMAIN 0xD002D11
44 #endif
45 
46 #ifdef LOG_TAG
47 #undef LOG_TAG
48 #define LOG_TAG "DfxUtil"
49 #endif
50 
51 namespace OHOS {
52 namespace HiviewDFX {
53 #ifndef is_host
TrimAndDupStr(const std::string & source,std::string & str)54 bool TrimAndDupStr(const std::string &source, std::string &str)
55 {
56     if (source.empty()) {
57         return false;
58     }
59 
60     const char *begin = source.data();
61     const char *end = begin + source.size();
62     if (begin == end) {
63         DFXLOG_ERROR("%s", "Source is empty");
64         return false;
65     }
66 
67     while ((begin < end) && isspace(*begin)) {
68         begin++;
69     }
70 
71     while ((begin < end) && isspace(*(end - 1))) {
72         end--;
73     }
74 
75     if (begin == end) {
76         return false;
77     }
78 
79     uint32_t maxStrLen = NAME_BUF_LEN;
80     uint32_t offset = static_cast<uint32_t>(end - begin);
81     if (maxStrLen > offset) {
82         maxStrLen = offset;
83     }
84 
85     str.assign(begin, maxStrLen);
86     return true;
87 }
88 
GetTimeMilliSeconds(void)89 uint64_t GetTimeMilliSeconds(void)
90 {
91     struct timespec ts;
92     (void)clock_gettime(CLOCK_REALTIME, &ts);
93     return ((uint64_t)ts.tv_sec * NUMBER_ONE_THOUSAND) + // 1000 : second to millisecond convert ratio
94         (((uint64_t)ts.tv_nsec) / NUMBER_ONE_MILLION); // 1000000 : nanosecond to millisecond convert ratio
95 }
96 
GetAbsTimeMilliSeconds(void)97 uint64_t GetAbsTimeMilliSeconds(void)
98 {
99     struct timespec ts;
100     (void)clock_gettime(CLOCK_MONOTONIC, &ts);
101     return (static_cast<uint64_t>(ts.tv_sec) * NUMBER_ONE_THOUSAND) +
102         (static_cast<uint64_t>(ts.tv_nsec) / NUMBER_ONE_MILLION);
103 }
104 
GetCurrentTimeStr(uint64_t current)105 std::string GetCurrentTimeStr(uint64_t current)
106 {
107     time_t now = time(nullptr);
108     uint64_t millsecond = 0;
109     const uint64_t ratio = NUMBER_ONE_THOUSAND;
110     if (current > static_cast<uint64_t>(now)) {
111         millsecond = current % ratio;
112         now = static_cast<time_t>(current / ratio);
113     }
114 
115     auto tm = std::localtime(&now);
116     char seconds[128] = {0}; // 128 : time buffer size
117     if (tm == nullptr || strftime(seconds, sizeof(seconds) - 1, "%Y-%m-%d %H:%M:%S", tm) == 0) {
118         return "invalid timestamp\n";
119     }
120 
121     char millBuf[256] = {0}; // 256 : milliseconds buffer size
122     int ret = snprintf_s(millBuf, sizeof(millBuf), sizeof(millBuf) - 1,
123         "%s.%03u\n", seconds, millsecond);
124     if (ret <= 0) {
125         return "invalid timestamp\n";
126     }
127     return std::string(millBuf, strlen(millBuf));
128 }
129 
ReadDirFiles(const std::string & path,std::vector<std::string> & files)130 bool ReadDirFiles(const std::string& path, std::vector<std::string>& files)
131 {
132     DIR *dir = opendir(path.c_str());
133     if (dir == nullptr) {
134         return false;
135     }
136 
137     struct dirent *ent;
138     while ((ent = readdir(dir)) != nullptr) {
139         // current dir OR parent dir
140         if ((strcmp(ent->d_name, ".") == 0) || (strcmp(ent->d_name, "..") == 0)) {
141             continue;
142         }
143         files.emplace_back(std::string(ent->d_name));
144     }
145     (void)closedir(dir);
146     return (files.size() > 0);
147 }
148 
VerifyFilePath(const std::string & filePath,const std::vector<const std::string> & validPaths)149 bool VerifyFilePath(const std::string& filePath, const std::vector<const std::string>& validPaths)
150 {
151     if (validPaths.size() == 0) {
152         return true;
153     }
154 
155     for (auto validPath : validPaths) {
156         if (filePath.find(validPath) == 0) {
157             return true;
158         }
159     }
160     return false;
161 }
162 
ParseSiValue(siginfo_t & si,uint64_t & endTime,int & tid)163 void ParseSiValue(siginfo_t& si, uint64_t& endTime, int& tid)
164 {
165     const int flagOffset = 63;
166     if ((reinterpret_cast<uint64_t>(si.si_value.sival_ptr) & (1ULL << flagOffset)) != 0) {
167         endTime = reinterpret_cast<uint64_t>(si.si_value.sival_ptr) & (~(1ULL << flagOffset));
168         tid = 0;
169     } else {
170         endTime = 0;
171         tid = si.si_value.sival_int;
172     }
173 }
174 #endif
175 
GetFileSize(const int & fd)176 off_t GetFileSize(const int& fd)
177 {
178     off_t fileSize = 0;
179     if (fd >= 0) {
180         struct stat fileStat;
181         if (fstat(fd, &fileStat) == 0) {
182             fileSize = fileStat.st_size;
183         }
184     }
185     return fileSize;
186 }
187 
ReadFdToString(int fd,std::string & content)188 bool ReadFdToString(int fd, std::string& content)
189 {
190     content.clear();
191     struct stat sb;
192     if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
193         content.reserve(sb.st_size);
194     }
195 
196     char buf[BUFSIZ] __attribute__((__uninitialized__));
197     ssize_t n;
198     while ((n = OHOS_TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
199         content.append(buf, n);
200     }
201     return (n == 0);
202 }
203 }   // namespace HiviewDFX
204 }   // namespace OHOS
205 
206 // this will also used for libunwinder head (out of namespace)
207 #if defined(is_mingw) && is_mingw
GetLastErrorString()208 std::string GetLastErrorString()
209 {
210     LPVOID lpMsgBuf;
211     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
212                       FORMAT_MESSAGE_IGNORE_INSERTS,
213                   NULL, GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, NULL);
214     std::string error((LPTSTR)lpMsgBuf);
215     LocalFree(lpMsgBuf);
216     return error;
217 }
218 
mmap(void * addr,size_t length,int prot,int flags,int fd,size_t offset)219 void *mmap(void *addr, size_t length, int prot, int flags, int fd, size_t offset)
220 {
221     HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
222     if (FileHandle == INVALID_HANDLE_VALUE) {
223         return MMAP_FAILED;
224     }
225 
226     LOGD("fd is %d", fd);
227 
228     HANDLE FileMappingHandle = ::CreateFileMappingW(FileHandle, 0, PAGE_READONLY, 0, 0, 0);
229     if (FileMappingHandle == nullptr) {
230         LOGE("CreateFileMappingW %zu Failed with %ld:%s", length, GetLastError(), GetLastErrorString().c_str());
231         return MMAP_FAILED;
232     }
233 
234     void *mapAddr = ::MapViewOfFile(FileMappingHandle, FILE_MAP_READ, 0, 0, 0);
235     if (mapAddr == nullptr) {
236         LOGE("MapViewOfFile %zu Failed with %ld:%s", length, GetLastError(), GetLastErrorString().c_str());
237         return MMAP_FAILED;
238     }
239 
240     // Close all the handles except for the view. It will keep the other handles
241     // alive.
242     ::CloseHandle(FileMappingHandle);
243     return mapAddr;
244 }
245 
munmap(void * addr,size_t)246 int munmap(void *addr, size_t)
247 {
248     /*
249         On success, munmap() returns 0.  On failure, it returns -1, and
250         errno is set to indicate the error (probably to EINVAL).
251 
252         UnmapViewOfFile function (memoryapi.h)
253 
254         If the function succeeds, the return value is nonzero.
255         If the function fails, the return value is zero. To get extended error information, call
256     GetLastError.
257     */
258     return !UnmapViewOfFile(addr);
259 }
260 #endif
261