• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
23 namespace OHOS {
24 namespace Developtools {
25 namespace NativeDaemon {
RoundUp(uint32_t x,const int align)26 uint32_t RoundUp(uint32_t x, const int align)
27 {
28     return (((x) + (align) >= 1 ? (x) + (align) - 1 : 0) / (align)) * (align);
29 }
30 
StringReplace(std::string source,const std::string & from,const std::string & to)31 std::string StringReplace(std::string source, const std::string &from, const std::string &to)
32 {
33     size_t pos = 0;
34     std::string result;
35     // find
36     while ((pos = source.find(from)) != std::string::npos) {
37         // replace
38         result.append(source.substr(0, pos) + to);
39         source.erase(0, pos + from.length());
40     }
41     // add last token
42     result.append(source);
43     return result;
44 }
45 
SubStringCount(const std::string & source,const std::string & sub)46 size_t SubStringCount(const std::string &source, const std::string &sub)
47 {
48     size_t count(0);
49     size_t pos(0);
50     if (sub.empty()) {
51         return source.size();
52     }
53     while ((pos = source.find(sub, pos)) != std::string::npos) {
54         pos += sub.size();
55         count++;
56     }
57     return count;
58 }
59 
StringSplit(std::string source,std::string split)60 std::vector<std::string> StringSplit(std::string source, std::string split)
61 {
62     size_t pos = 0;
63     std::vector<std::string> result;
64 
65     // find
66     if (!split.empty()) {
67         while ((pos = source.find(split)) != std::string::npos) {
68             // split
69             std::string token = source.substr(0, pos);
70             if (!token.empty()) {
71                 result.push_back(token);
72             }
73             source.erase(0, pos + split.length());
74         }
75     }
76     // add last token
77     if (!source.empty()) {
78         result.push_back(source);
79     }
80     return result;
81 }
82 
AdvancedSplitString(const std::string_view & str,const std::string & delimiters,std::vector<std::string> & elems)83 void AdvancedSplitString(const std::string_view& str, const std::string& delimiters, std::vector<std::string>& elems)
84 {
85     std::string::size_type pos = 0;
86     std::string::size_type prev = 0;
87     while ((pos = str.find_first_of(delimiters, prev)) != std::string::npos) {
88         if (pos > prev) {
89             elems.emplace_back(str, prev, pos - prev);
90         }
91         prev = pos + 1;
92     }
93 
94     if (prev < str.size()) {
95         elems.emplace_back(str, prev, str.size() - prev);
96     }
97 }
98 
StdoutRecord(const std::string & tempFile,const std::string & mode)99 StdoutRecord::StdoutRecord(const std::string &tempFile, const std::string &mode)
100 {
101     if (!tempFile.empty()) {
102         recordFile_ = fopen(tempFile.c_str(), mode.c_str());
103         if (recordFile_ == nullptr) {
104             HLOGE("tmpfile create failed '%s' with mode '%s'", tempFile.c_str(), mode.c_str());
105         } else {
106             // auto start it
107             Start();
108         }
109     }
110 }
Start()111 bool StdoutRecord::Start()
112 {
113     content_ = EMPTY_STRING;
114     fflush(stdout);
115 
116     // we will save output here
117     if (recordFile_ == nullptr) {
118         recordFile_ = std::tmpfile();
119     }
120     if (recordFile_ == nullptr) {
121         // try second way
122         std::string fileName = "/data/local/tmp/temp.stdout";
123         recordFile_ = fopen(fileName.c_str(), "w+");
124         if (recordFile_ == nullptr) {
125             HLOGF("tmpfile create failed '%s'", fileName.c_str());
126             return false;
127         }
128     }
129 
130     // we save the stdout
131     stdoutFile_ = OHOS::UniqueFd(dup(STDOUT_FILENO));
132     if (stdoutFile_ == -1) {
133         HLOGF("std dup failed");
134         return false;
135     }
136 
137     // setup temp file as stdout
138     if (dup2(fileno(recordFile_), STDOUT_FILENO) != -1) {
139         stop_ = false;
140         return true;
141     } else {
142         HLOGF("std dup2 failed");
143         return false;
144     }
145 }
146 
Stop()147 std::string StdoutRecord::Stop()
148 {
149     if (stop_)
150         return content_;
151     fflush(stdout);
152     // restore fd
153     dup2(stdoutFile_, STDOUT_FILENO);
154 
155     // return file content
156     if (recordFile_ != nullptr) {
157         const long fileLength = lseek(fileno(recordFile_), 0, SEEK_END);
158         content_.resize(fileLength);
159         lseek(fileno(recordFile_), 0, SEEK_SET);
160         const long len = read(fileno(recordFile_), content_.data(), fileLength);
161         std::fclose(recordFile_);
162         recordFile_ = nullptr;
163         if (len < 0) {
164             HLOGE("tmp file read failed (try read %ld)", fileLength);
165         } else if (len < fileLength) {
166             HLOGE("not all the data is read, lost %ld/%ld bytes", fileLength - len, fileLength);
167         }
168     } else {
169         HLOGE("recordFile_ is nullptr");
170     }
171     stop_ = true;
172     return content_;
173 }
174 
IsDigits(const std::string & str)175 bool IsDigits(const std::string &str)
176 {
177     if (str.empty()) {
178         return false;
179     } else {
180         return std::all_of(str.begin(), str.end(), ::isdigit);
181     }
182 }
183 
IsHexDigits(const std::string & str)184 bool IsHexDigits(const std::string &str)
185 {
186     if (str.empty()) {
187         return false;
188     }
189     const std::string prefix {"0x"};
190     std::string effectStr {str};
191     if (prefix.compare(0, prefix.size(), effectStr.substr(0, prefix.size())) == 0) {
192         effectStr = effectStr.substr(prefix.size(), effectStr.size() - prefix.size());
193     }
194     if (effectStr.empty()) {
195         return false;
196     }
197     std::size_t start {0};
198     for (; start < effectStr.size(); ++start) {
199         if (effectStr[start] == '0') {
200             continue;
201         }
202         break;
203     }
204     if (start == effectStr.size()) {
205         effectStr = "0";
206     }
207     return std::all_of(effectStr.begin(), effectStr.end(), ::isxdigit);
208 }
209 
IsDir(const std::string & path)210 bool IsDir(const std::string &path)
211 {
212     struct stat st;
213     if (stat(path.c_str(), &st) == 0) {
214         return S_ISDIR(st.st_mode);
215     }
216     return false;
217 }
218 
IsPath(const std::string & fileName)219 bool IsPath(const std::string &fileName)
220 {
221     HLOG_ASSERT(!fileName.empty());
222     if (fileName[0] == PATH_SEPARATOR) {
223         return true;
224     }
225     const int prefixPathLen = 2;
226     if (fileName.substr(0, prefixPathLen) == "./") {
227         return true;
228     }
229     return false;
230 }
231 
PlatformPathConvert(const std::string & path)232 std::string PlatformPathConvert(const std::string &path)
233 {
234 #if is_mingw
235     return StringReplace(path, "/", "\\");
236 #else
237     return path;
238 #endif
239 }
240 
ReadFileToString(const std::string & fileName)241 std::string ReadFileToString(const std::string &fileName)
242 {
243     std::ifstream inputString(fileName, std::ios::in);
244     if (!inputString) {
245         return EMPTY_STRING;
246     }
247     std::istreambuf_iterator<char> firstIt = {inputString};
248     std::istreambuf_iterator<char> lastIt = {};
249 
250     std::string content(firstIt, lastIt);
251     return content;
252 }
253 
ReadFileToString(const std::string & fileName,std::string & fileData,size_t fileSize)254 bool ReadFileToString(const std::string &fileName, std::string &fileData, size_t fileSize)
255 {
256     fileData.clear();
257     OHOS::UniqueFd fd(open(fileName.c_str(), O_RDONLY | O_BINARY));
258     if (fileSize == 0) {
259         struct stat fileStat;
260         if (fstat(fd.Get(), &fileStat) != -1 && fileStat.st_size > 0) {
261             fileData.reserve(fileStat.st_size);
262         }
263     } else {
264         fileData.reserve(fileSize);
265     }
266 
267     char buf[BUFSIZ] __attribute__((__uninitialized__));
268     ssize_t readSize;
269     while ((readSize = read(fd.Get(), &buf[0], sizeof(buf))) > 0) {
270         fileData.append(buf, readSize);
271     }
272     return (readSize == 0) ? true : false;
273 }
274 
WriteStringToFile(const std::string & fileName,const std::string & value)275 bool WriteStringToFile(const std::string &fileName, const std::string &value)
276 {
277     std::ofstream output(fileName, std::ios::out);
278     if (!output) {
279         return false;
280     }
281     output << value;
282 
283     return output.good();
284 }
285 
IsRoot()286 bool IsRoot()
287 {
288 #if is_linux || is_ohos
289     static bool isRoot = (getuid() == 0);
290     return isRoot;
291 #else
292     return true;
293 #endif
294 }
295 
PowerOfTwo(int n)296 bool PowerOfTwo(int n)
297 {
298     return n && (!(n & (n - 1)));
299 }
300 
ReadIntFromProcFile(const std::string & path,int & value)301 bool ReadIntFromProcFile(const std::string &path, int &value)
302 {
303     std::string s = ReadFileToString(path);
304     if (s.empty()) {
305         return false;
306     }
307     value = std::stoi(s);
308     return true;
309 }
310 
WriteIntToProcFile(const std::string & path,int value)311 bool WriteIntToProcFile(const std::string &path, int value)
312 {
313     std::string s = std::to_string(value);
314 
315     return WriteStringToFile(path, s);
316 }
317 
318 // compress specified dataFile into gzip file
CompressFile(const std::string & dataFile,const std::string & destFile)319 bool CompressFile(const std::string &dataFile, const std::string &destFile)
320 {
321     FILE *fp = fopen(dataFile.c_str(), "rb");
322     if (fp == nullptr) {
323         HLOGE("Fail to open data file %s", dataFile.c_str());
324         perror("Fail to fopen(rb)");
325         return false;
326     }
327 
328     std::unique_ptr<gzFile_s, decltype(&gzclose)> fgz(gzopen(destFile.c_str(), "wb"), gzclose);
329     if (fgz == nullptr) {
330         HLOGE("Fail to call gzopen(%s)", destFile.c_str());
331         fclose(fp);
332         return false;
333     }
334 
335     std::vector<char> buf(COMPRESS_READ_BUF_SIZE);
336     size_t len = 0;
337     while ((len = fread(buf.data(), sizeof(uint8_t), buf.size(), fp))) {
338         if (gzwrite(fgz.get(), buf.data(), len) == 0) {
339             HLOGE("Fail to call gzwrite for %zu bytes", len);
340             fclose(fp);
341             return false;
342         }
343     }
344     if (!feof(fp)) {
345         if (ferror(fp) != 0) {
346             HLOGE("ferror return err");
347             fclose(fp);
348             return false;
349         }
350     }
351     const int errBufSize = 256;
352     char errBuf[errBufSize] = { 0 };
353     strerror_r(errno, errBuf, errBufSize);
354     UNWIND_CHECK_TRUE(fclose(fp) == 0, false, "fclose failed! errno(%d:%s)", errno, errBuf);
355     return true;
356 }
357 
358 // uncompress specified gzip file into dataFile
UncompressFile(const std::string & gzipFile,const std::string & dataFile)359 bool UncompressFile(const std::string &gzipFile, const std::string &dataFile)
360 {
361     FILE *fp = fopen(dataFile.c_str(), "wb");
362     if (fp == nullptr) {
363         HLOGE("Fail to open data file %s", dataFile.c_str());
364         perror("Fail to fopen(rb)");
365         return false;
366     }
367     std::unique_ptr<gzFile_s, decltype(&gzclose)> fgz(gzopen(gzipFile.c_str(), "rb"), gzclose);
368     if (fgz == nullptr) {
369         HLOGE("Fail to call gzopen(%s)", gzipFile.c_str());
370         fclose(fp);
371         return false;
372     }
373 
374     std::vector<char> buf(COMPRESS_READ_BUF_SIZE);
375     z_size_t len = 0;
376     while ((len = gzfread(buf.data(), sizeof(uint8_t), buf.size(), fgz.get()))) {
377         if (len != fwrite(buf.data(), sizeof(uint8_t), len, fp)) {
378             HLOGE("Fail to call fwrite for %zu bytes", len);
379             fclose(fp);
380             return false;
381         }
382     }
383     if (!gzeof(fgz.get())) {
384         int rc = 0;
385         const char *err = gzerror(fgz.get(), &rc);
386         if (rc != Z_OK) {
387             HLOGE("gzfread return %d:%s", rc, err);
388             fclose(fp);
389             return false;
390         }
391     }
392     const int size = 256;
393     char errBuf[size] = { 0 };
394     strerror_r(errno, errBuf, size);
395     UNWIND_CHECK_TRUE(fclose(fp) == 0, false, "fclose failed! errno(%d:%s)", errno, errBuf);
396     return true;
397 }
398 
StringTrim(std::string & string)399 std::string &StringTrim(std::string &string)
400 {
401     if (!string.empty()) {
402         string.erase(0, string.find_first_not_of(" "));
403         string.erase(string.find_last_not_of(" ") + 1);
404     }
405     return string;
406 }
407 
GetEntriesInDir(const std::string & basePath)408 std::vector<std::string> GetEntriesInDir(const std::string &basePath)
409 {
410     std::vector<std::string> result;
411     DIR *dir = opendir(basePath.c_str());
412     if (dir == nullptr) {
413         return result;
414     }
415     dirent *entry;
416     while ((entry = readdir(dir)) != nullptr) {
417         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
418             continue;
419         }
420         result.push_back(entry->d_name);
421     }
422     closedir(dir);
423     return result;
424 }
425 
GetSubDirs(const std::string & basePath)426 std::vector<std::string> GetSubDirs(const std::string &basePath)
427 {
428     std::vector<std::string> entries = GetEntriesInDir(basePath);
429     std::vector<std::string> result = {};
430     for (std::size_t index = 0; index < entries.size(); ++index) {
431         if (IsDir(basePath + "/" + entries[index])) {
432             result.push_back(std::move(entries[index]));
433         }
434     }
435     return result;
436 }
437 
IsSameCommand(std::string cmdLine,std::string cmdName)438 bool IsSameCommand(std::string cmdLine, std::string cmdName)
439 {
440     std::vector<std::string> cmdpaths = StringSplit(cmdLine, "/");
441     if (!cmdpaths.empty()) {
442         if (strcmp(cmdpaths.back().c_str(), cmdName.c_str()) == 0) {
443             return true;
444         }
445     }
446     return false;
447 }
448 
GetSubthreadIDs(const pid_t pid)449 std::vector<pid_t> GetSubthreadIDs(const pid_t pid)
450 {
451     std::string path {"/proc/"};
452     path += std::to_string(pid);
453     path += "/task/";
454     auto tids = GetSubDirs(path);
455     std::vector<pid_t> res {};
456     for (auto tidStr : tids) {
457         pid_t tid = static_cast<pid_t>(std::stoul(tidStr, nullptr));
458         if (tid == pid) {
459             continue;
460         }
461         res.push_back(tid);
462     }
463     return res;
464 }
465 
StringStartsWith(const std::string & string,const std::string & with)466 bool StringStartsWith(const std::string &string, const std::string &with)
467 {
468     return string.find(with) == 0;
469 }
470 
StringEndsWith(const std::string & string,const std::string & with)471 bool StringEndsWith(const std::string &string, const std::string &with)
472 {
473     if (string.empty()) {
474         // empty string only end with empty string
475         if (with.empty()) {
476             return true;
477         } else {
478             return false;
479         }
480     }
481     return string.rfind(with) == (string.length() - with.length());
482 }
483 
HexDump(const uint8_t * buf,size_t size,size_t maxSize)484 void HexDump(const uint8_t *buf, size_t size, size_t maxSize)
485 {
486     const unsigned char *byteBuf = static_cast<const unsigned char *>(buf);
487     const size_t dumpByteEachLine = 8;
488     size_t outputBytes = 0;
489     if (!maxSize) {
490         outputBytes = size;
491     } else {
492         outputBytes = std::min(size, maxSize);
493     }
494 
495     for (size_t i = 0; i <= outputBytes; i += dumpByteEachLine) {
496         HLOGM(" %02zu: %s ", i, BufferToHexString(byteBuf, dumpByteEachLine).c_str());
497         byteBuf += dumpByteEachLine;
498     }
499 }
500 
BufferToHexString(const std::vector<unsigned char> & vec)501 std::string BufferToHexString(const std::vector<unsigned char> &vec)
502 {
503     return BufferToHexString(vec.data(), vec.size());
504 }
505 
BufferToHexString(const unsigned char buf[],size_t size)506 std::string BufferToHexString(const unsigned char buf[], size_t size)
507 {
508     std::stringstream ss;
509     ss << size << ":";
510     for (size_t i = 0; i < size; i++) {
511         ss << " 0x" << std::setfill('0') << std::setw(BYTE_PRINT_WIDTH) << std::hex
512            << (unsigned short)buf[i];
513     }
514     return ss.str();
515 }
516 
GetProcessPid(const std::string & processName)517 int32_t GetProcessPid(const std::string& processName)
518 {
519     std::string cmd = "pidof " + processName;
520     std::unique_ptr<FILE, decltype(&pclose)> runCmd(popen(cmd.c_str(), "r"), pclose);
521     if (runCmd == nullptr) {
522         return 0;
523     }
524 
525     constexpr uint32_t readBufferSize = 16;
526     std::array<char, readBufferSize> buffer;
527     std::string result;
528     while (fgets(buffer.data(), buffer.size(), runCmd.get()) != nullptr) {
529         result = buffer.data();
530     }
531     return std::atoi(result.c_str());
532 }
IsArkJsFile(const std::string & filepath)533 bool IsArkJsFile(const std::string& filepath)
534 {
535     return (StringEndsWith(filepath, ".hap") || StringEndsWith(filepath, ".hsp") ||
536             StringStartsWith(filepath, "[anon:ArkTS Code") || StringEndsWith(filepath, ".abc"));
537 }
538 } // namespace NativeDaemon
539 } // namespace Developtools
540 } // namespace OHOS
541 
542 // this will also used for libunwind head (out of namespace)
543 #if is_mingw
544 using namespace OHOS::Developtools::NativeDaemon;
GetLastErrorString()545 std::string GetLastErrorString()
546 {
547     LPVOID lpMsgBuf;
548     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
549                   FORMAT_MESSAGE_IGNORE_INSERTS,
550                   nullptr, GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, nullptr);
551     std::string error((LPTSTR)lpMsgBuf);
552     LocalFree(lpMsgBuf);
553     return error;
554 }
555 
mmap(void * addr,size_t length,int prot,int flags,int fd,size_t offset)556 void *mmap(void *addr, size_t length, int prot, int flags, int fd, size_t offset)
557 {
558     HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
559     if (FileHandle == INVALID_HANDLE_VALUE) {
560         return MMAP_FAILED;
561     }
562 
563     HLOGV("fd is %d", fd);
564 
565     HANDLE FileMappingHandle = ::CreateFileMappingW(FileHandle, 0, PAGE_READONLY, 0, 0, 0);
566     UNWIND_CHECK_NOTNULL(FileMappingHandle, MMAP_FAILED, "CreateFileMappingW %zu Failed with %ld:%s",
567                          length, GetLastError(), GetLastErrorString().c_str());
568 
569     void *mapAddr = ::MapViewOfFile(FileMappingHandle, FILE_MAP_READ, 0, 0, 0);
570     UNWIND_CHECK_NOTNULL(mapAddr, MMAP_FAILED, "MapViewOfFile %zu Failed with %ld:%s",
571                          length, GetLastError(), GetLastErrorString().c_str());
572 
573     // Close all the handles except for the view. It will keep the other handles
574     // alive.
575     ::CloseHandle(FileMappingHandle);
576     return mapAddr;
577 }
578 
munmap(void * addr,size_t)579 int munmap(void *addr, size_t)
580 {
581     /*
582         On success, munmap() returns 0.  On failure, it returns -1, and
583         errno is set to indicate the error (probably to EINVAL).
584 
585         UnmapViewOfFile function (memoryapi.h)
586 
587         If the function succeeds, the return value is nonzero.
588         If the function fails, the return value is zero. To get extended error information, call
589     GetLastError.
590     */
591     return !UnmapViewOfFile(addr);
592 }
593 #endif