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