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