1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 #include "utilities.h"
16
17 #include <zlib.h>
18 #if is_mingw
19 #include <io.h>
20 #endif
21 #include "logging.h"
22 #include "common.h"
23
24 namespace OHOS {
25 namespace Developtools {
26 namespace NativeDaemon {
27 constexpr uint32_t INT_MAX_LEN = 10;
28 constexpr uint32_t SC_LG_TINY_MIN = 3;
29 constexpr uint32_t LG_QUANTUM = 4;
30 constexpr uint32_t SC_NTINY = LG_QUANTUM - SC_LG_TINY_MIN;
31 constexpr uint32_t SC_LG_TINY_MAXCLASS = (LG_QUANTUM > SC_LG_TINY_MIN ? LG_QUANTUM - 1 : -1);
32 constexpr uint32_t SC_LG_NGROUP = 2;
33 constexpr uint32_t LG_SIZE_CLASS_GROUP = 2;
34 constexpr uint32_t NTBINS = 1;
35 constexpr uint32_t LG_TINY_MAXCLASS = 3;
36 constexpr uint32_t RIGHT_MOVE_1 = 1;
37 constexpr uint32_t RIGHT_MOVE_2 = 2;
38 constexpr uint32_t RIGHT_MOVE_4 = 4;
39 constexpr uint32_t RIGHT_MOVE_8 = 8;
40 constexpr uint32_t RIGHT_MOVE_16 = 16;
41
RoundUp(uint32_t x,const int align)42 uint32_t RoundUp(uint32_t x, const int align)
43 {
44 return (((x) + (align) >= 1 ? (x) + (align) - 1 : 0) / (align)) * (align);
45 }
46
StringReplace(std::string source,const std::string & from,const std::string & to)47 std::string StringReplace(std::string source, const std::string &from, const std::string &to)
48 {
49 size_t pos = 0;
50 while ((pos = source.find(from)) != std::string::npos) {
51 // replace
52 source.replace(pos, from.length(), to);
53 }
54 return source;
55 }
56
GetValueFromJsonFile(const std::string & filePath,const std::string & key)57 int GetValueFromJsonFile(const std::string& filePath, const std::string& key)
58 {
59 std::ifstream inFile(filePath, std::ios::in);
60 int result = -1; // 默认返回值
61 if (!inFile.is_open()) {
62 HLOGE("parse json file: %s is not existed.", filePath.c_str());
63 return result;
64 }
65 std::string fileContent((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
66 cJSON* jsonNode = cJSON_Parse(fileContent.c_str());
67 inFile.close();
68
69 if (jsonNode == nullptr) {
70 HLOGE("parse json file: %s failed.", filePath.c_str());
71 return result;
72 }
73 do {
74 cJSON* valueNode = cJSON_GetObjectItem(jsonNode, key.c_str());
75 if (valueNode == nullptr) {
76 HLOGE("ParseJson hiprofiler_hook_process_count json node not found.");
77 break;
78 }
79 if (!cJSON_IsNumber(valueNode)) {
80 HLOGE("ParseJson: hiprofiler_hook_process_count item is illegal.");
81 break;
82 }
83 result = valueNode->valueint; // 获取整数值
84 } while (false);
85
86 // 释放 cJSON 结构体占用的内存
87 cJSON_Delete(jsonNode);
88 return result;
89 }
90
SubStringCount(const std::string & source,const std::string & sub)91 size_t SubStringCount(const std::string &source, const std::string &sub)
92 {
93 size_t count(0);
94 size_t pos(0);
95 if (sub.empty()) {
96 return source.size();
97 }
98 while ((pos = source.find(sub, pos)) != std::string::npos) {
99 pos += sub.size();
100 count++;
101 }
102 return count;
103 }
104
StringSplit(std::string source,std::string split)105 std::vector<std::string> StringSplit(std::string source, std::string split)
106 {
107 size_t pos = 0;
108 std::vector<std::string> result;
109
110 // find
111 if (!split.empty()) {
112 while ((pos = source.find(split)) != std::string::npos) {
113 // split
114 std::string token = source.substr(0, pos);
115 if (!token.empty()) {
116 result.push_back(token);
117 }
118 source.erase(0, pos + split.length());
119 }
120 }
121 // add last token
122 if (!source.empty()) {
123 result.push_back(source);
124 }
125 return result;
126 }
127
AdvancedSplitString(const std::string_view & str,const std::string & delimiters,std::vector<std::string> & elems)128 void AdvancedSplitString(const std::string_view& str, const std::string& delimiters, std::vector<std::string>& elems)
129 {
130 std::string::size_type pos = 0;
131 std::string::size_type prev = 0;
132 while ((pos = str.find_first_of(delimiters, prev)) != std::string::npos) {
133 if (pos > prev) {
134 elems.emplace_back(str, prev, pos - prev);
135 }
136 prev = pos + 1;
137 }
138
139 if (prev < str.size()) {
140 elems.emplace_back(str, prev, str.size() - prev);
141 }
142 }
143
StdoutRecord(const std::string & tempFile,const std::string & mode)144 StdoutRecord::StdoutRecord(const std::string &tempFile, const std::string &mode)
145 {
146 if (!tempFile.empty()) {
147 recordFile_ = fopen(tempFile.c_str(), mode.c_str());
148 if (recordFile_ == nullptr) {
149 HLOGE("tmpfile create failed '%s' with mode '%s'", tempFile.c_str(), mode.c_str());
150 } else {
151 // auto start it
152 Start();
153 }
154 }
155 }
Start()156 bool StdoutRecord::Start()
157 {
158 content_ = EMPTY_STRING;
159 fflush(stdout);
160
161 // we will save output here
162 if (recordFile_ == nullptr) {
163 recordFile_ = std::tmpfile();
164 }
165 if (recordFile_ == nullptr) {
166 // try second way
167 std::string fileName = "/data/local/tmp/temp.stdout";
168 recordFile_ = fopen(fileName.c_str(), "w+");
169 if (recordFile_ == nullptr) {
170 HLOGF("tmpfile create failed '%s'", fileName.c_str());
171 return false;
172 }
173 }
174
175 // we save the stdout
176 stdoutFile_ = OHOS::UniqueFd(dup(STDOUT_FILENO));
177 if (stdoutFile_ == -1) {
178 HLOGF("std dup failed");
179 return false;
180 }
181
182 // setup temp file as stdout
183 if (dup2(fileno(recordFile_), STDOUT_FILENO) != -1) {
184 stop_ = false;
185 return true;
186 } else {
187 HLOGF("std dup2 failed");
188 return false;
189 }
190 }
191
Stop()192 std::string StdoutRecord::Stop()
193 {
194 if (stop_)
195 return content_;
196 fflush(stdout);
197 // restore fd
198 dup2(stdoutFile_, STDOUT_FILENO);
199
200 // return file content
201 if (recordFile_ != nullptr) {
202 const long fileLength = lseek(fileno(recordFile_), 0, SEEK_END);
203 content_.resize(fileLength);
204 lseek(fileno(recordFile_), 0, SEEK_SET);
205 const long len = read(fileno(recordFile_), content_.data(), fileLength);
206 std::fclose(recordFile_);
207 recordFile_ = nullptr;
208 if (len < 0) {
209 HLOGE("tmp file read failed (try read %ld)", fileLength);
210 } else if (len < fileLength) {
211 HLOGE("not all the data is read, lost %ld/%ld bytes", fileLength - len, fileLength);
212 }
213 } else {
214 HLOGE("recordFile_ is nullptr");
215 }
216 stop_ = true;
217 return content_;
218 }
219
IsDigits(const std::string & str)220 bool IsDigits(const std::string &str)
221 {
222 if (str.empty() || str.size() >= INT_MAX_LEN) {
223 return false;
224 } else {
225 return std::all_of(str.begin(), str.end(), ::isdigit);
226 }
227 }
228
IsHexDigits(const std::string & str)229 bool IsHexDigits(const std::string &str)
230 {
231 if (str.empty()) {
232 return false;
233 }
234 const std::string prefix {"0x"};
235 std::string effectStr {str};
236 if (prefix.compare(0, prefix.size(), effectStr.substr(0, prefix.size())) == 0) {
237 effectStr = effectStr.substr(prefix.size(), effectStr.size() - prefix.size());
238 }
239 if (effectStr.empty()) {
240 return false;
241 }
242 std::size_t start {0};
243 for (; start < effectStr.size(); ++start) {
244 if (effectStr[start] == '0') {
245 continue;
246 }
247 break;
248 }
249 if (start == effectStr.size()) {
250 effectStr = "0";
251 }
252 return std::all_of(effectStr.begin(), effectStr.end(), ::isxdigit);
253 }
254
LgFloor(unsigned long val)255 unsigned LgFloor(unsigned long val)
256 {
257 val |= (val >> RIGHT_MOVE_1);
258 val |= (val >> RIGHT_MOVE_2);
259 val |= (val >> RIGHT_MOVE_4);
260 val |= (val >> RIGHT_MOVE_8);
261 val |= (val >> RIGHT_MOVE_16);
262 if (sizeof(val) > 4) { // 4: sizeThreshold
263 int constant = sizeof(val) * 4; // 4: sizeThreshold
264 val |= (val >> constant);
265 }
266 val++;
267 if (val == 0) {
268 return 8 * sizeof(val) - 1; // 8: 8byte
269 }
270 return __builtin_ffsl(val) - 2; // 2: adjustment
271 }
272
PowCeil(uint64_t val)273 uint64_t PowCeil(uint64_t val)
274 {
275 size_t msbIndex = LgFloor(val - 1);
276 return 1ULL << (msbIndex + 1);
277 }
278
ComputeAlign(size_t size)279 size_t ComputeAlign(size_t size)
280 {
281 if (size == 0) {
282 return 0;
283 }
284 unsigned index = 0;
285 if (size <= (static_cast<size_t>(1) << SC_LG_TINY_MAXCLASS)) {
286 unsigned lgTmin = SC_LG_TINY_MAXCLASS - SC_NTINY + 1;
287 unsigned lgCeil = LgFloor(PowCeil(size));
288 index = (lgCeil < lgTmin) ? 0 : lgCeil - lgTmin;
289 } else {
290 unsigned floor = LgFloor((size << 1) - 1);
291 unsigned shift = (floor < SC_LG_NGROUP + LG_QUANTUM) ? 0 : floor - (SC_LG_NGROUP + LG_QUANTUM);
292 unsigned grp = shift << SC_LG_NGROUP;
293 unsigned lgDelta = (floor < SC_LG_NGROUP + LG_QUANTUM + 1) ? LG_QUANTUM : floor - SC_LG_NGROUP - 1;
294 size_t deltaInverseMask = static_cast<size_t>(-1) << lgDelta;
295 unsigned mod = ((((size - 1) & deltaInverseMask) >> lgDelta)) & ((static_cast<size_t>(1) << SC_LG_NGROUP) - 1);
296 index = SC_NTINY + grp + mod;
297 }
298
299 if (index < NTBINS) {
300 return (static_cast<size_t>(1) << (LG_TINY_MAXCLASS - NTBINS + 1 + index));
301 }
302 size_t reducedIndex = index - NTBINS;
303 size_t grpVal = reducedIndex >> LG_SIZE_CLASS_GROUP;
304 size_t modVal = reducedIndex & ((static_cast<size_t>(1) << LG_SIZE_CLASS_GROUP) - 1);
305 size_t grpSizeMask = ~((!!grpVal) - 1);
306 size_t grpSize = ((static_cast<size_t>(1) << (LG_QUANTUM + (LG_SIZE_CLASS_GROUP - 1))) << grpVal) & grpSizeMask;
307 size_t shiftVal = (grpVal == 0) ? 1 : grpVal;
308 size_t lgDeltaVal = shiftVal + (LG_QUANTUM - 1);
309 size_t modSize = (modVal + 1) << lgDeltaVal;
310 size_t usize = grpSize + modSize;
311 return usize;
312 }
313
IsDir(const std::string & path)314 bool IsDir(const std::string &path)
315 {
316 struct stat st;
317 if (stat(path.c_str(), &st) == 0) {
318 return S_ISDIR(st.st_mode);
319 }
320 return false;
321 }
322
IsPath(const std::string & fileName)323 bool IsPath(const std::string &fileName)
324 {
325 HLOG_ASSERT(!fileName.empty());
326 if (fileName[0] == PATH_SEPARATOR) {
327 return true;
328 }
329 const int prefixPathLen = 2;
330 if (fileName.substr(0, prefixPathLen) == "./") {
331 return true;
332 }
333 return false;
334 }
335
PlatformPathConvert(const std::string & path)336 std::string PlatformPathConvert(const std::string &path)
337 {
338 #if is_mingw
339 return StringReplace(path, "/", "\\");
340 #else
341 return path;
342 #endif
343 }
344
ReadFileToString(const std::string & fileName)345 std::string ReadFileToString(const std::string &fileName)
346 {
347 std::ifstream inputString(fileName, std::ios::in);
348 if (!inputString) {
349 return EMPTY_STRING;
350 }
351 std::istreambuf_iterator<char> firstIt = {inputString};
352 std::istreambuf_iterator<char> lastIt = {};
353
354 std::string content(firstIt, lastIt);
355 return content;
356 }
357
ReadFileToString(const std::string & fileName,std::string & fileData,size_t fileSize)358 bool ReadFileToString(const std::string &fileName, std::string &fileData, size_t fileSize)
359 {
360 fileData.clear();
361 OHOS::UniqueFd fd(open(fileName.c_str(), O_RDONLY | O_BINARY));
362 if (fileSize == 0) {
363 struct stat fileStat;
364 if (fstat(fd.Get(), &fileStat) != -1 && fileStat.st_size > 0) {
365 fileData.reserve(fileStat.st_size);
366 }
367 } else {
368 fileData.reserve(fileSize);
369 }
370
371 char buf[BUFSIZ] __attribute__((__uninitialized__));
372 ssize_t readSize;
373 while ((readSize = read(fd.Get(), &buf[0], sizeof(buf))) > 0) {
374 fileData.append(buf, readSize);
375 }
376 return (readSize == 0) ? true : false;
377 }
378
WriteStringToFile(const std::string & fileName,const std::string & value)379 bool WriteStringToFile(const std::string &fileName, const std::string &value)
380 {
381 std::ofstream output(fileName, std::ios::out);
382 if (!output) {
383 return false;
384 }
385 output << value;
386
387 return output.good();
388 }
389
PowerOfTwo(int n)390 bool PowerOfTwo(int n)
391 {
392 return n && (!(n & (n - 1)));
393 }
394
ReadIntFromProcFile(const std::string & path,int & value)395 bool ReadIntFromProcFile(const std::string &path, int &value)
396 {
397 std::string s = ReadFileToString(path);
398 if (s.empty()) {
399 return false;
400 }
401 value = IsDigits(s) ? std::stoi(s) : 0;
402 return true;
403 }
404
WriteIntToProcFile(const std::string & path,int value)405 bool WriteIntToProcFile(const std::string &path, int value)
406 {
407 std::string s = std::to_string(value);
408
409 return WriteStringToFile(path, s);
410 }
411
412 // compress specified dataFile into gzip file
CompressFile(const std::string & dataFile,const std::string & destFile)413 bool CompressFile(const std::string &dataFile, const std::string &destFile)
414 {
415 FILE *fp = fopen(dataFile.c_str(), "rb");
416 if (fp == nullptr) {
417 HLOGE("Fail to open data file %s", dataFile.c_str());
418 perror("Fail to fopen(rb)");
419 return false;
420 }
421
422 std::unique_ptr<gzFile_s, decltype(&gzclose)> fgz(gzopen(destFile.c_str(), "wb"), gzclose);
423 if (fgz == nullptr) {
424 HLOGE("Fail to call gzopen(%s)", destFile.c_str());
425 fclose(fp);
426 return false;
427 }
428
429 std::vector<char> buf(COMPRESS_READ_BUF_SIZE);
430 size_t len = 0;
431 while ((len = fread(buf.data(), sizeof(uint8_t), buf.size(), fp))) {
432 if (gzwrite(fgz.get(), buf.data(), len) == 0) {
433 HLOGE("Fail to call gzwrite for %zu bytes", len);
434 fclose(fp);
435 return false;
436 }
437 }
438 if (!feof(fp)) {
439 if (ferror(fp) != 0) {
440 HLOGE("ferror return err");
441 fclose(fp);
442 return false;
443 }
444 }
445 const int errBufSize = 256;
446 char errBuf[errBufSize] = { 0 };
447 strerror_r(errno, errBuf, errBufSize);
448 UNWIND_CHECK_TRUE(fclose(fp) == 0, false, "fclose failed! errno(%d:%s)", errno, errBuf);
449 return true;
450 }
451
452 // uncompress specified gzip file into dataFile
UncompressFile(const std::string & gzipFile,const std::string & dataFile)453 bool UncompressFile(const std::string &gzipFile, const std::string &dataFile)
454 {
455 FILE *fp = fopen(dataFile.c_str(), "wb");
456 if (fp == nullptr) {
457 HLOGE("Fail to open data file %s", dataFile.c_str());
458 perror("Fail to fopen(rb)");
459 return false;
460 }
461 std::unique_ptr<gzFile_s, decltype(&gzclose)> fgz(gzopen(gzipFile.c_str(), "rb"), gzclose);
462 if (fgz == nullptr) {
463 HLOGE("Fail to call gzopen(%s)", gzipFile.c_str());
464 fclose(fp);
465 return false;
466 }
467
468 std::vector<char> buf(COMPRESS_READ_BUF_SIZE);
469 z_size_t len = 0;
470 while ((len = gzfread(buf.data(), sizeof(uint8_t), buf.size(), fgz.get()))) {
471 if (len != fwrite(buf.data(), sizeof(uint8_t), len, fp)) {
472 HLOGE("Fail to call fwrite for %zu bytes", len);
473 fclose(fp);
474 return false;
475 }
476 }
477 if (!gzeof(fgz.get())) {
478 int rc = 0;
479 const char *err = gzerror(fgz.get(), &rc);
480 if (rc != Z_OK) {
481 HLOGE("gzfread return %d:%s", rc, err);
482 fclose(fp);
483 return false;
484 }
485 }
486 const int size = 256;
487 char errBuf[size] = { 0 };
488 strerror_r(errno, errBuf, size);
489 UNWIND_CHECK_TRUE(fclose(fp) == 0, false, "fclose failed! errno(%d:%s)", errno, errBuf);
490 return true;
491 }
492
StringTrim(std::string & string)493 std::string &StringTrim(std::string &string)
494 {
495 if (!string.empty()) {
496 string.erase(0, string.find_first_not_of(" "));
497 string.erase(string.find_last_not_of(" ") + 1);
498 }
499 return string;
500 }
501
GetEntriesInDir(const std::string & basePath)502 std::vector<std::string> GetEntriesInDir(const std::string &basePath)
503 {
504 std::vector<std::string> result;
505 DIR *dir = opendir(basePath.c_str());
506 if (dir == nullptr) {
507 return result;
508 }
509 dirent *entry;
510 while ((entry = readdir(dir)) != nullptr) {
511 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
512 continue;
513 }
514 result.push_back(entry->d_name);
515 }
516 closedir(dir);
517 return result;
518 }
519
GetSubDirs(const std::string & basePath)520 std::vector<std::string> GetSubDirs(const std::string &basePath)
521 {
522 std::vector<std::string> entries = GetEntriesInDir(basePath);
523 std::vector<std::string> result = {};
524 for (std::size_t index = 0; index < entries.size(); ++index) {
525 if (IsDir(basePath + "/" + entries[index])) {
526 result.push_back(std::move(entries[index]));
527 }
528 }
529 return result;
530 }
531
IsSameCommand(std::string cmdLine,std::string cmdName)532 bool IsSameCommand(std::string cmdLine, std::string cmdName)
533 {
534 std::vector<std::string> cmdpaths = StringSplit(cmdLine, "/");
535 if (!cmdpaths.empty()) {
536 if (strcmp(cmdpaths.back().c_str(), cmdName.c_str()) == 0) {
537 return true;
538 }
539 }
540 return false;
541 }
542
GetSubthreadIDs(const pid_t pid)543 std::vector<pid_t> GetSubthreadIDs(const pid_t pid)
544 {
545 std::string path {"/proc/"};
546 path += std::to_string(pid);
547 path += "/task/";
548 auto tids = GetSubDirs(path);
549 std::vector<pid_t> res {};
550 for (auto tidStr : tids) {
551 pid_t tid = static_cast<pid_t>(std::stoul(tidStr, nullptr));
552 if (tid == pid) {
553 continue;
554 }
555 res.push_back(tid);
556 }
557 return res;
558 }
559
StringStartsWith(const std::string & string,const std::string & with)560 bool StringStartsWith(const std::string &string, const std::string &with)
561 {
562 return string.find(with) == 0;
563 }
564
StringEndsWith(const std::string & string,const std::string & with)565 bool StringEndsWith(const std::string &string, const std::string &with)
566 {
567 if (string.empty()) {
568 // empty string only end with empty string
569 if (with.empty()) {
570 return true;
571 } else {
572 return false;
573 }
574 }
575 return string.rfind(with) == (string.length() - with.length());
576 }
577
HexDump(const uint8_t * buf,size_t size,size_t maxSize)578 void HexDump(const uint8_t *buf, size_t size, size_t maxSize)
579 {
580 const unsigned char *byteBuf = static_cast<const unsigned char *>(buf);
581 const size_t dumpByteEachLine = 8;
582 size_t outputBytes = 0;
583 if (!maxSize) {
584 outputBytes = size;
585 } else {
586 outputBytes = std::min(size, maxSize);
587 }
588
589 for (size_t i = 0; i <= outputBytes; i += dumpByteEachLine) {
590 HLOGM(" %02zu: %s ", i, BufferToHexString(byteBuf, dumpByteEachLine).c_str());
591 byteBuf += dumpByteEachLine;
592 }
593 }
594
BufferToHexString(const std::vector<unsigned char> & vec)595 std::string BufferToHexString(const std::vector<unsigned char> &vec)
596 {
597 return BufferToHexString(vec.data(), vec.size());
598 }
599
BufferToHexString(const unsigned char buf[],size_t size)600 std::string BufferToHexString(const unsigned char buf[], size_t size)
601 {
602 std::stringstream ss;
603 ss << size << ":";
604 for (size_t i = 0; i < size; i++) {
605 ss << " 0x" << std::setfill('0') << std::setw(BYTE_PRINT_WIDTH) << std::hex
606 << (unsigned short)buf[i];
607 }
608 return ss.str();
609 }
610
GetProcessPid(const std::string & processName)611 int32_t GetProcessPid(const std::string& processName)
612 {
613 int32_t pidValue = -1;
614 COMMON::IsProcessExist(processName, pidValue);
615 return pidValue;
616 }
IsArkJsFile(const std::string & filepath)617 bool IsArkJsFile(const std::string& filepath)
618 {
619 return (StringEndsWith(filepath, ".hap") || StringEndsWith(filepath, ".hsp") ||
620 StringStartsWith(filepath, "[anon:ArkTS Code") || StringEndsWith(filepath, ".abc")
621 || StringEndsWith(filepath, ".hqf"));
622 }
623
StripPac(uintptr_t inAddr,uintptr_t pacMask)624 uintptr_t StripPac(uintptr_t inAddr, uintptr_t pacMask)
625 {
626 uintptr_t outAddr = inAddr;
627 #if defined(__aarch64__)
628 if (outAddr != 0) {
629 if (pacMask != 0) {
630 outAddr &= ~pacMask;
631 } else {
632 register uint64_t x30 __asm("x30") = inAddr;
633 asm("hint 0x7" : "+r"(x30));
634 outAddr = x30;
635 }
636 }
637 #endif
638 return outAddr;
639 }
640 } // namespace NativeDaemon
641 } // namespace Developtools
642 } // namespace OHOS
643
644 // this will also used for libunwind head (out of namespace)
645 #if is_mingw
646 using namespace OHOS::Developtools::NativeDaemon;
GetLastErrorString()647 std::string GetLastErrorString()
648 {
649 LPVOID lpMsgBuf;
650 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
651 FORMAT_MESSAGE_IGNORE_INSERTS,
652 nullptr, GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, nullptr);
653 std::string error((LPTSTR)lpMsgBuf);
654 LocalFree(lpMsgBuf);
655 return error;
656 }
657
mmap(void * addr,size_t length,int prot,int flags,int fd,size_t offset)658 void *mmap(void *addr, size_t length, int prot, int flags, int fd, size_t offset)
659 {
660 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
661 if (FileHandle == INVALID_HANDLE_VALUE) {
662 return MMAP_FAILED;
663 }
664
665 HLOGV("fd is %d", fd);
666
667 HANDLE FileMappingHandle = ::CreateFileMappingW(FileHandle, 0, PAGE_READONLY, 0, 0, 0);
668 UNWIND_CHECK_NOTNULL(FileMappingHandle, MMAP_FAILED, "CreateFileMappingW %zu Failed with %ld:%s",
669 length, GetLastError(), GetLastErrorString().c_str());
670
671 void *mapAddr = ::MapViewOfFile(FileMappingHandle, FILE_MAP_READ, 0, 0, 0);
672 UNWIND_CHECK_NOTNULL(mapAddr, MMAP_FAILED, "MapViewOfFile %zu Failed with %ld:%s",
673 length, GetLastError(), GetLastErrorString().c_str());
674
675 // Close all the handles except for the view. It will keep the other handles
676 // alive.
677 ::CloseHandle(FileMappingHandle);
678 return mapAddr;
679 }
680
munmap(void * addr,size_t)681 int munmap(void *addr, size_t)
682 {
683 /*
684 On success, munmap() returns 0. On failure, it returns -1, and
685 errno is set to indicate the error (probably to EINVAL).
686
687 UnmapViewOfFile function (memoryapi.h)
688
689 If the function succeeds, the return value is nonzero.
690 If the function fails, the return value is zero. To get extended error information, call
691 GetLastError.
692 */
693 return !UnmapViewOfFile(addr);
694 }
695 #endif