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 51namespace OHOS { 52namespace HiviewDFX { 53#ifndef is_host 54bool 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 DFXLOGE("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 89uint64_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 97uint64_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 105std::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 130bool 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 149bool 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 163void 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 176off_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 188bool 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 208std::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 219void *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 DFXLOGD("fd is %{public}d", fd); 227 228 HANDLE FileMappingHandle = ::CreateFileMappingW(FileHandle, 0, PAGE_READONLY, 0, 0, 0); 229 if (FileMappingHandle == nullptr) { 230 DFXLOGE("CreateFileMappingW %{public}zu Failed with %{public}ld:%{public}s", 231 length, GetLastError(), GetLastErrorString().c_str()); 232 return MMAP_FAILED; 233 } 234 235 void *mapAddr = ::MapViewOfFile(FileMappingHandle, FILE_MAP_READ, 0, 0, 0); 236 if (mapAddr == nullptr) { 237 DFXLOGE("MapViewOfFile %{public}zu Failed with %{public}ld:%{public}s", 238 length, GetLastError(), GetLastErrorString().c_str()); 239 return MMAP_FAILED; 240 } 241 242 // Close all the handles except for the view. It will keep the other handles 243 // alive. 244 ::CloseHandle(FileMappingHandle); 245 return mapAddr; 246} 247 248int munmap(void *addr, size_t) 249{ 250 /* 251 On success, munmap() returns 0. On failure, it returns -1, and 252 errno is set to indicate the error (probably to EINVAL). 253 254 UnmapViewOfFile function (memoryapi.h) 255 256 If the function succeeds, the return value is nonzero. 257 If the function fails, the return value is zero. To get extended error information, call 258 GetLastError. 259 */ 260 return !UnmapViewOfFile(addr); 261} 262#endif 263