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