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
GetCurrentTimeStr(uint64_t current)97 std::string GetCurrentTimeStr(uint64_t current)
98 {
99 time_t now = time(nullptr);
100 uint64_t millsecond = 0;
101 const uint64_t ratio = NUMBER_ONE_THOUSAND;
102 if (current > static_cast<uint64_t>(now)) {
103 millsecond = current % ratio;
104 now = static_cast<time_t>(current / ratio);
105 }
106
107 auto tm = std::localtime(&now);
108 char seconds[128] = {0}; // 128 : time buffer size
109 if (tm == nullptr || strftime(seconds, sizeof(seconds) - 1, "%Y-%m-%d %H:%M:%S", tm) == 0) {
110 return "invalid timestamp\n";
111 }
112
113 char millBuf[256] = {0}; // 256 : milliseconds buffer size
114 int ret = snprintf_s(millBuf, sizeof(millBuf), sizeof(millBuf) - 1,
115 "%s.%03u\n", seconds, millsecond);
116 if (ret <= 0) {
117 return "invalid timestamp\n";
118 }
119 return std::string(millBuf, strlen(millBuf));
120 }
121
ReadDirFiles(const std::string & path,std::vector<std::string> & files)122 bool ReadDirFiles(const std::string& path, std::vector<std::string>& files)
123 {
124 DIR *dir = opendir(path.c_str());
125 if (dir == nullptr) {
126 return false;
127 }
128
129 struct dirent *ent;
130 while ((ent = readdir(dir)) != nullptr) {
131 // current dir OR parent dir
132 if ((strcmp(ent->d_name, ".") == 0) || (strcmp(ent->d_name, "..") == 0)) {
133 continue;
134 }
135 files.emplace_back(std::string(ent->d_name));
136 }
137 (void)closedir(dir);
138 return (files.size() > 0);
139 }
140
ReadDirFilesByPid(const int & pid,std::vector<std::string> & files)141 bool ReadDirFilesByPid(const int& pid, std::vector<std::string>& files)
142 {
143 char path[PATH_LEN] = {0};
144 #if is_ohos
145 if (pid == getprocpid()) {
146 #else
147 if (pid == getpid()) {
148 #endif
149 if (snprintf_s(path, sizeof(path), sizeof(path) - 1, PROC_SELF_TASK_PATH) <= 0) {
150 return false;
151 }
152 } else {
153 if (snprintf_s(path, sizeof(path), sizeof(path) - 1, "/proc/%d/task", pid) <= 0) {
154 return false;
155 }
156 }
157
158 char realPath[PATH_MAX];
159 if (!realpath(path, realPath)) {
160 return false;
161 }
162 return ReadDirFiles(realPath, files);
163 }
164
165 bool VerifyFilePath(const std::string& filePath, const std::vector<const std::string>& validPaths)
166 {
167 if (validPaths.size() == 0) {
168 return true;
169 }
170
171 for (auto validPath : validPaths) {
172 if (filePath.find(validPath) == 0) {
173 return true;
174 }
175 }
176 return false;
177 }
178 #endif
179
180 off_t GetFileSize(const int& fd)
181 {
182 off_t fileSize = 0;
183 if (fd >= 0) {
184 struct stat fileStat;
185 if (fstat(fd, &fileStat) == 0) {
186 fileSize = fileStat.st_size;
187 }
188 }
189 return fileSize;
190 }
191
192 bool ReadFdToString(int fd, std::string& content)
193 {
194 content.clear();
195 struct stat sb;
196 if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
197 content.reserve(sb.st_size);
198 }
199
200 char buf[BUFSIZ] __attribute__((__uninitialized__));
201 ssize_t n;
202 while ((n = OHOS_TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
203 content.append(buf, n);
204 }
205 return (n == 0);
206 }
207 } // namespace HiviewDFX
208 } // namespace OHOS
209
210 // this will also used for libunwinder head (out of namespace)
211 #if defined(is_mingw) && is_mingw
GetLastErrorString()212 std::string GetLastErrorString()
213 {
214 LPVOID lpMsgBuf;
215 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
216 FORMAT_MESSAGE_IGNORE_INSERTS,
217 NULL, GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, NULL);
218 std::string error((LPTSTR)lpMsgBuf);
219 LocalFree(lpMsgBuf);
220 return error;
221 }
222
mmap(void * addr,size_t length,int prot,int flags,int fd,size_t offset)223 void *mmap(void *addr, size_t length, int prot, int flags, int fd, size_t offset)
224 {
225 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
226 if (FileHandle == INVALID_HANDLE_VALUE) {
227 return MMAP_FAILED;
228 }
229
230 LOGD("fd is %d", fd);
231
232 HANDLE FileMappingHandle = ::CreateFileMappingW(FileHandle, 0, PAGE_READONLY, 0, 0, 0);
233 if (FileMappingHandle == nullptr) {
234 LOGE("CreateFileMappingW %zu Failed with %ld:%s", length, GetLastError(), GetLastErrorString().c_str());
235 return MMAP_FAILED;
236 }
237
238 void *mapAddr = ::MapViewOfFile(FileMappingHandle, FILE_MAP_READ, 0, 0, 0);
239 if (mapAddr == nullptr) {
240 LOGE("MapViewOfFile %zu Failed with %ld:%s", length, GetLastError(), GetLastErrorString().c_str());
241 return MMAP_FAILED;
242 }
243
244 // Close all the handles except for the view. It will keep the other handles
245 // alive.
246 ::CloseHandle(FileMappingHandle);
247 return mapAddr;
248 }
249
munmap(void * addr,size_t)250 int munmap(void *addr, size_t)
251 {
252 /*
253 On success, munmap() returns 0. On failure, it returns -1, and
254 errno is set to indicate the error (probably to EINVAL).
255
256 UnmapViewOfFile function (memoryapi.h)
257
258 If the function succeeds, the return value is nonzero.
259 If the function fails, the return value is zero. To get extended error information, call
260 GetLastError.
261 */
262 return !UnmapViewOfFile(addr);
263 }
264 #endif
265