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