1 /*
2 * Copyright (c) 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 #ifdef _WIN32
17 #include <io.h>
18 #else
19 #include <unistd.h>
20 #endif
21 #include <sys/stat.h>
22 #include <ctime>
23 #include <sstream>
24 #include "ecmascript/dfx/hprof/rawheap_translate/utils.h"
25
26 namespace rawheap_translate {
RealPath(const std::string & filename,std::string & realpath)27 bool RealPath(const std::string &filename, std::string &realpath)
28 {
29 if (filename.empty() || filename.size() > PATH_MAX) {
30 LOG_ERROR_ << "filename is illegal!";
31 return false;
32 }
33
34 #ifdef _WIN32
35 if (_access(filename.c_str(), 0) < 0) {
36 #else
37 if (access(filename.c_str(), 0) < 0) {
38 #endif
39 LOG_ERROR_ << "file can not access! filePath=" << filename;
40 return false;
41 }
42
43 char resolvedPath[PATH_MAX];
44 if (strcpy_s(resolvedPath, PATH_MAX, filename.c_str()) != 0) {
45 return false;
46 }
47
48 realpath = resolvedPath;
49 return true;
50 }
51
52 bool FileCheckAndOpenBinary(const std::string &rawheapPath, std::ifstream &file, uint32_t &fileSize)
53 {
54 std::string realpath {};
55 if (!RealPath(rawheapPath, realpath)) {
56 LOG_ERROR_ << "file path is illegal! filePath: " << rawheapPath;
57 return false;
58 }
59
60 uint64_t size = FileReader::GetFileSize(realpath);
61 if (size == 0 || size >= MAX_FILE_SIZE) {
62 LOG_ERROR_ << "file size >= 4GB or size = 0, unsupported!";
63 return false;
64 }
65
66 fileSize = static_cast<uint32_t>(size);
67 file.open(realpath, std::ios::binary);
68 return true;
69 }
70
71 bool GenerateDumpFileName(std::string &filename)
72 {
73 std::time_t t = std::time(nullptr);
74 struct tm *now = localtime(&t);
75 if (now == nullptr) {
76 LOG_ERROR_ << "failed to converting time to local time!";
77 return false;
78 }
79
80 filename = "hprof_";
81 const int timeStart = 1900; // 1900: means the start of timestamp
82 filename += std::to_string(now->tm_year + timeStart);
83 filename += '-' + std::to_string(now->tm_mon + 1);
84 filename += '-' + std::to_string(now->tm_mday);
85 filename += '-' + std::to_string(now->tm_hour);
86 filename += '-' + std::to_string(now->tm_min);
87 filename += '-' + std::to_string(now->tm_sec);
88 filename += ".heapsnapshot";
89 return true;
90 }
91
92 bool EndsWith(const std::string &str, const std::string &suffix)
93 {
94 if (str.length() < suffix.length()) {
95 return false;
96 }
97 std::string subStr = str.substr(str.length() - suffix.length(), str.length());
98 return subStr == suffix;
99 }
100
101 bool IsLittleEndian()
102 {
103 int i = 1;
104 return *reinterpret_cast<char *>(&i) == 1;
105 }
106
107 uint16_t ByteToU16(char *data)
108 {
109 uint32_t value = *reinterpret_cast<uint16_t *>(data);
110 if (!IsLittleEndian()) {
111 value = (value & 0x00FF) << 8 |
112 (value & 0xFF00) >> 8;
113 }
114 return value;
115 }
116
117 uint32_t ByteToU32(char *data)
118 {
119 uint32_t value = *reinterpret_cast<uint32_t *>(data);
120 if (!IsLittleEndian()) {
121 value = (value & 0x000000FF) << 24 |
122 (value & 0x0000FF00) << 8 |
123 (value & 0x00FF0000) >> 8 |
124 (value & 0xFF000000) >> 24;
125 }
126 return value;
127 }
128
129 uint64_t ByteToU64(char *data)
130 {
131 uint64_t value = *reinterpret_cast<uint64_t *>(data);
132 if (!IsLittleEndian()) {
133 value = (value & 0x00000000000000FF) << 56 |
134 (value & 0x000000000000FF00) << 40 |
135 (value & 0x0000000000FF0000) << 24 |
136 (value & 0x00000000FF000000) << 8 |
137 (value & 0x000000FF00000000) >> 8 |
138 (value & 0x0000FF00000000) >> 24 |
139 (value & 0x00FF0000000000) >> 40 |
140 (value & 0xFF000000000000) >> 56;
141 }
142 return value;
143 }
144
145 void ByteToU32Array(char *data, uint32_t *array, uint32_t size)
146 {
147 char *num = data;
148 for (uint32_t i = 0; i < size; i++) {
149 array[i] = ByteToU32(num);
150 num += sizeof(uint32_t);
151 }
152 }
153
154 void ByteToU64Array(char *data, uint64_t *array, uint32_t size)
155 {
156 char *num = data;
157 for (uint32_t i = 0; i < size; i++) {
158 array[i] = ByteToU64(num);
159 num += sizeof(uint64_t);
160 }
161 }
162
163 bool FileReader::Initialize(const std::string &path)
164 {
165 std::string realPath;
166 if (!RealPath(path, realPath)) {
167 return false;
168 }
169
170 file_.open(realPath, std::ios::binary);
171 fileSize_= GetFileSize(realPath);
172 return true;
173 }
174
175 bool FileReader::Read(char *buf, uint32_t size)
176 {
177 if (buf == nullptr) {
178 LOG_ERROR_ << "file buf is nullptr!";
179 return false;
180 }
181 if (file_.read(buf, size).fail()) {
182 LOG_ERROR_ << "read failed!";
183 return false;
184 }
185 return true;
186 }
187
188 bool FileReader::Seek(uint32_t offset)
189 {
190 if (!file_.is_open()) {
191 LOG_ERROR_ << "file not open!";
192 return false;
193 }
194 file_.clear();
195 if (!file_.seekg(offset)) {
196 LOG_ERROR_ << "set file offset failed, offset=" << offset;
197 return false;
198 }
199 return true;
200 }
201
202 bool FileReader::ReadArray(std::vector<uint32_t> &array, uint32_t size)
203 {
204 uint32_t dataSize = size * sizeof(uint32_t);
205 std::vector<char> data(dataSize);
206 if (!Read(data.data(), dataSize)) {
207 return false;
208 }
209 ByteToU32Array(data.data(), array.data(), size);
210 return true;
211 }
212
213 bool FileReader::ReadArray(std::vector<uint64_t> &array, uint32_t size)
214 {
215 uint32_t dataSize = size * sizeof(uint64_t);
216 std::vector<char> data(dataSize);
217 if (!Read(data.data(), dataSize)) {
218 return false;
219 }
220 ByteToU64Array(data.data(), array.data(), size);
221 return true;
222 }
223
224 bool FileReader::CheckAndGetHeaderAt(uint32_t offset, uint32_t assertNum)
225 {
226 constexpr int HEADER_SIZE = sizeof(uint64_t) / sizeof(uint32_t);
227 std::vector<uint32_t> header(HEADER_SIZE);
228 if (!Seek(offset) || !ReadArray(header, HEADER_SIZE)) {
229 return false;
230 }
231
232 uint32_t first = header[0];
233 uint32_t second = header[1];
234 if (assertNum != 0 && second != assertNum) {
235 return false;
236 }
237
238 left_ = first;
239 right_ = second;
240 return true;
241 }
242
243 uint32_t FileReader::GetFileSize(const std::string &path)
244 {
245 if (path.empty()) {
246 return 0;
247 }
248 struct stat fileInfo;
249 if (stat(path.c_str(), &fileInfo) == 0) {
250 return static_cast<uint32_t>(fileInfo.st_size);
251 }
252 return 0;
253 }
254
255 bool Version::Parse(const std::string &version)
256 {
257 std::vector<int> result {};
258 std::stringstream ss(version);
259 std::string token;
260 while (getline(ss, token, '.')) {
261 int number;
262 std::istringstream(token) >> number;
263 result.push_back(number);
264 }
265
266 if (result.size() != 3) {
267 LOG_ERROR_ << "parse version failed! version=" << version;
268 return false;
269 }
270
271 major_ = result[0];
272 minor_ = result[1];
273 build_ = result[2];
274 return true;
275 }
276 } // namespace rawheap_translate
277