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