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