xref: /aosp_15_r20/system/extras/simpleperf/utils.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include "utils.h"
18*288bf522SAndroid Build Coastguard Worker 
19*288bf522SAndroid Build Coastguard Worker #include <dirent.h>
20*288bf522SAndroid Build Coastguard Worker #include <errno.h>
21*288bf522SAndroid Build Coastguard Worker #include <fcntl.h>
22*288bf522SAndroid Build Coastguard Worker #include <inttypes.h>
23*288bf522SAndroid Build Coastguard Worker #include <stdarg.h>
24*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
25*288bf522SAndroid Build Coastguard Worker #include <sys/stat.h>
26*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
27*288bf522SAndroid Build Coastguard Worker 
28*288bf522SAndroid Build Coastguard Worker #include <algorithm>
29*288bf522SAndroid Build Coastguard Worker #include <map>
30*288bf522SAndroid Build Coastguard Worker #include <string>
31*288bf522SAndroid Build Coastguard Worker 
32*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
33*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
34*288bf522SAndroid Build Coastguard Worker #include <android-base/parseint.h>
35*288bf522SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
36*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
37*288bf522SAndroid Build Coastguard Worker #include <build/version.h>
38*288bf522SAndroid Build Coastguard Worker 
39*288bf522SAndroid Build Coastguard Worker #include <7zCrc.h>
40*288bf522SAndroid Build Coastguard Worker #include <Xz.h>
41*288bf522SAndroid Build Coastguard Worker #include <XzCrc64.h>
42*288bf522SAndroid Build Coastguard Worker 
43*288bf522SAndroid Build Coastguard Worker #include "RegEx.h"
44*288bf522SAndroid Build Coastguard Worker #include "environment.h"
45*288bf522SAndroid Build Coastguard Worker 
46*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
47*288bf522SAndroid Build Coastguard Worker 
48*288bf522SAndroid Build Coastguard Worker using android::base::ParseInt;
49*288bf522SAndroid Build Coastguard Worker using android::base::Split;
50*288bf522SAndroid Build Coastguard Worker using android::base::StringPrintf;
51*288bf522SAndroid Build Coastguard Worker 
Clear()52*288bf522SAndroid Build Coastguard Worker void OneTimeFreeAllocator::Clear() {
53*288bf522SAndroid Build Coastguard Worker   for (auto& p : v_) {
54*288bf522SAndroid Build Coastguard Worker     delete[] p;
55*288bf522SAndroid Build Coastguard Worker   }
56*288bf522SAndroid Build Coastguard Worker   v_.clear();
57*288bf522SAndroid Build Coastguard Worker   cur_ = nullptr;
58*288bf522SAndroid Build Coastguard Worker   end_ = nullptr;
59*288bf522SAndroid Build Coastguard Worker }
60*288bf522SAndroid Build Coastguard Worker 
AllocateString(std::string_view s)61*288bf522SAndroid Build Coastguard Worker const char* OneTimeFreeAllocator::AllocateString(std::string_view s) {
62*288bf522SAndroid Build Coastguard Worker   size_t size = s.size() + 1;
63*288bf522SAndroid Build Coastguard Worker   if (cur_ + size > end_) {
64*288bf522SAndroid Build Coastguard Worker     size_t alloc_size = std::max(size, unit_size_);
65*288bf522SAndroid Build Coastguard Worker     char* p = new char[alloc_size];
66*288bf522SAndroid Build Coastguard Worker     v_.push_back(p);
67*288bf522SAndroid Build Coastguard Worker     cur_ = p;
68*288bf522SAndroid Build Coastguard Worker     end_ = p + alloc_size;
69*288bf522SAndroid Build Coastguard Worker   }
70*288bf522SAndroid Build Coastguard Worker   memcpy(cur_, s.data(), s.size());
71*288bf522SAndroid Build Coastguard Worker   cur_[s.size()] = '\0';
72*288bf522SAndroid Build Coastguard Worker   const char* result = cur_;
73*288bf522SAndroid Build Coastguard Worker   cur_ += size;
74*288bf522SAndroid Build Coastguard Worker   return result;
75*288bf522SAndroid Build Coastguard Worker }
76*288bf522SAndroid Build Coastguard Worker 
OpenReadOnly(const std::string & filename)77*288bf522SAndroid Build Coastguard Worker android::base::unique_fd FileHelper::OpenReadOnly(const std::string& filename) {
78*288bf522SAndroid Build Coastguard Worker   int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY | O_BINARY));
79*288bf522SAndroid Build Coastguard Worker   return android::base::unique_fd(fd);
80*288bf522SAndroid Build Coastguard Worker }
81*288bf522SAndroid Build Coastguard Worker 
OpenWriteOnly(const std::string & filename)82*288bf522SAndroid Build Coastguard Worker android::base::unique_fd FileHelper::OpenWriteOnly(const std::string& filename) {
83*288bf522SAndroid Build Coastguard Worker   int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), O_WRONLY | O_BINARY | O_CREAT, 0644));
84*288bf522SAndroid Build Coastguard Worker   return android::base::unique_fd(fd);
85*288bf522SAndroid Build Coastguard Worker }
86*288bf522SAndroid Build Coastguard Worker 
CreateInstance(const std::string & filename)87*288bf522SAndroid Build Coastguard Worker std::unique_ptr<ArchiveHelper> ArchiveHelper::CreateInstance(const std::string& filename) {
88*288bf522SAndroid Build Coastguard Worker   android::base::unique_fd fd = FileHelper::OpenReadOnly(filename);
89*288bf522SAndroid Build Coastguard Worker   if (fd == -1) {
90*288bf522SAndroid Build Coastguard Worker     return nullptr;
91*288bf522SAndroid Build Coastguard Worker   }
92*288bf522SAndroid Build Coastguard Worker   // Simpleperf relies on ArchiveHelper to check if a file is zip file. We expect much more elf
93*288bf522SAndroid Build Coastguard Worker   // files than zip files in a process map. In order to detect invalid zip files fast, we add a
94*288bf522SAndroid Build Coastguard Worker   // check of magic number here. Note that OpenArchiveFd() detects invalid zip files in a thorough
95*288bf522SAndroid Build Coastguard Worker   // way, but it usually needs reading at least 64K file data.
96*288bf522SAndroid Build Coastguard Worker   static const char zip_preamble[] = {0x50, 0x4b, 0x03, 0x04};
97*288bf522SAndroid Build Coastguard Worker   char buf[4];
98*288bf522SAndroid Build Coastguard Worker   if (!android::base::ReadFully(fd, buf, 4) || memcmp(buf, zip_preamble, 4) != 0) {
99*288bf522SAndroid Build Coastguard Worker     return nullptr;
100*288bf522SAndroid Build Coastguard Worker   }
101*288bf522SAndroid Build Coastguard Worker   if (lseek(fd, 0, SEEK_SET) == -1) {
102*288bf522SAndroid Build Coastguard Worker     return nullptr;
103*288bf522SAndroid Build Coastguard Worker   }
104*288bf522SAndroid Build Coastguard Worker   ZipArchiveHandle handle;
105*288bf522SAndroid Build Coastguard Worker   int result = OpenArchiveFd(fd.release(), filename.c_str(), &handle);
106*288bf522SAndroid Build Coastguard Worker   if (result != 0) {
107*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to open archive " << filename << ": " << ErrorCodeString(result);
108*288bf522SAndroid Build Coastguard Worker     return nullptr;
109*288bf522SAndroid Build Coastguard Worker   }
110*288bf522SAndroid Build Coastguard Worker   return std::unique_ptr<ArchiveHelper>(new ArchiveHelper(handle, filename));
111*288bf522SAndroid Build Coastguard Worker }
112*288bf522SAndroid Build Coastguard Worker 
~ArchiveHelper()113*288bf522SAndroid Build Coastguard Worker ArchiveHelper::~ArchiveHelper() {
114*288bf522SAndroid Build Coastguard Worker   CloseArchive(handle_);
115*288bf522SAndroid Build Coastguard Worker }
116*288bf522SAndroid Build Coastguard Worker 
IterateEntries(const std::function<bool (ZipEntry &,const std::string &)> & callback)117*288bf522SAndroid Build Coastguard Worker bool ArchiveHelper::IterateEntries(
118*288bf522SAndroid Build Coastguard Worker     const std::function<bool(ZipEntry&, const std::string&)>& callback) {
119*288bf522SAndroid Build Coastguard Worker   void* iteration_cookie;
120*288bf522SAndroid Build Coastguard Worker   if (StartIteration(handle_, &iteration_cookie) < 0) {
121*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to iterate " << filename_;
122*288bf522SAndroid Build Coastguard Worker     return false;
123*288bf522SAndroid Build Coastguard Worker   }
124*288bf522SAndroid Build Coastguard Worker   ZipEntry zentry;
125*288bf522SAndroid Build Coastguard Worker   std::string zname;
126*288bf522SAndroid Build Coastguard Worker   int result;
127*288bf522SAndroid Build Coastguard Worker   while ((result = Next(iteration_cookie, &zentry, &zname)) == 0) {
128*288bf522SAndroid Build Coastguard Worker     if (!callback(zentry, zname)) {
129*288bf522SAndroid Build Coastguard Worker       break;
130*288bf522SAndroid Build Coastguard Worker     }
131*288bf522SAndroid Build Coastguard Worker   }
132*288bf522SAndroid Build Coastguard Worker   EndIteration(iteration_cookie);
133*288bf522SAndroid Build Coastguard Worker   if (result == -2) {
134*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to iterate " << filename_;
135*288bf522SAndroid Build Coastguard Worker     return false;
136*288bf522SAndroid Build Coastguard Worker   }
137*288bf522SAndroid Build Coastguard Worker   return true;
138*288bf522SAndroid Build Coastguard Worker }
139*288bf522SAndroid Build Coastguard Worker 
FindEntry(const std::string & name,ZipEntry * entry)140*288bf522SAndroid Build Coastguard Worker bool ArchiveHelper::FindEntry(const std::string& name, ZipEntry* entry) {
141*288bf522SAndroid Build Coastguard Worker   int result = ::FindEntry(handle_, name, entry);
142*288bf522SAndroid Build Coastguard Worker   if (result != 0) {
143*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to find " << name << " in " << filename_;
144*288bf522SAndroid Build Coastguard Worker     return false;
145*288bf522SAndroid Build Coastguard Worker   }
146*288bf522SAndroid Build Coastguard Worker   return true;
147*288bf522SAndroid Build Coastguard Worker }
148*288bf522SAndroid Build Coastguard Worker 
GetEntryData(ZipEntry & entry,std::vector<uint8_t> * data)149*288bf522SAndroid Build Coastguard Worker bool ArchiveHelper::GetEntryData(ZipEntry& entry, std::vector<uint8_t>* data) {
150*288bf522SAndroid Build Coastguard Worker   data->resize(entry.uncompressed_length);
151*288bf522SAndroid Build Coastguard Worker   if (ExtractToMemory(handle_, &entry, data->data(), data->size()) != 0) {
152*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to extract entry at " << entry.offset << " in " << filename_;
153*288bf522SAndroid Build Coastguard Worker     return false;
154*288bf522SAndroid Build Coastguard Worker   }
155*288bf522SAndroid Build Coastguard Worker   return true;
156*288bf522SAndroid Build Coastguard Worker }
157*288bf522SAndroid Build Coastguard Worker 
GetFd()158*288bf522SAndroid Build Coastguard Worker int ArchiveHelper::GetFd() {
159*288bf522SAndroid Build Coastguard Worker   return GetFileDescriptor(handle_);
160*288bf522SAndroid Build Coastguard Worker }
161*288bf522SAndroid Build Coastguard Worker 
PrintIndented(size_t indent,const char * fmt,...)162*288bf522SAndroid Build Coastguard Worker void PrintIndented(size_t indent, const char* fmt, ...) {
163*288bf522SAndroid Build Coastguard Worker   va_list ap;
164*288bf522SAndroid Build Coastguard Worker   va_start(ap, fmt);
165*288bf522SAndroid Build Coastguard Worker   printf("%*s", static_cast<int>(indent * 2), "");
166*288bf522SAndroid Build Coastguard Worker   vprintf(fmt, ap);
167*288bf522SAndroid Build Coastguard Worker   va_end(ap);
168*288bf522SAndroid Build Coastguard Worker }
169*288bf522SAndroid Build Coastguard Worker 
FprintIndented(FILE * fp,size_t indent,const char * fmt,...)170*288bf522SAndroid Build Coastguard Worker void FprintIndented(FILE* fp, size_t indent, const char* fmt, ...) {
171*288bf522SAndroid Build Coastguard Worker   va_list ap;
172*288bf522SAndroid Build Coastguard Worker   va_start(ap, fmt);
173*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "%*s", static_cast<int>(indent * 2), "");
174*288bf522SAndroid Build Coastguard Worker   vfprintf(fp, fmt, ap);
175*288bf522SAndroid Build Coastguard Worker   va_end(ap);
176*288bf522SAndroid Build Coastguard Worker }
177*288bf522SAndroid Build Coastguard Worker 
IsPowerOfTwo(uint64_t value)178*288bf522SAndroid Build Coastguard Worker bool IsPowerOfTwo(uint64_t value) {
179*288bf522SAndroid Build Coastguard Worker   return (value != 0 && ((value & (value - 1)) == 0));
180*288bf522SAndroid Build Coastguard Worker }
181*288bf522SAndroid Build Coastguard Worker 
GetEntriesInDir(const std::string & dirpath)182*288bf522SAndroid Build Coastguard Worker std::vector<std::string> GetEntriesInDir(const std::string& dirpath) {
183*288bf522SAndroid Build Coastguard Worker   std::vector<std::string> result;
184*288bf522SAndroid Build Coastguard Worker   DIR* dir = opendir(dirpath.c_str());
185*288bf522SAndroid Build Coastguard Worker   if (dir == nullptr) {
186*288bf522SAndroid Build Coastguard Worker     PLOG(DEBUG) << "can't open dir " << dirpath;
187*288bf522SAndroid Build Coastguard Worker     return result;
188*288bf522SAndroid Build Coastguard Worker   }
189*288bf522SAndroid Build Coastguard Worker   dirent* entry;
190*288bf522SAndroid Build Coastguard Worker   while ((entry = readdir(dir)) != nullptr) {
191*288bf522SAndroid Build Coastguard Worker     if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
192*288bf522SAndroid Build Coastguard Worker       continue;
193*288bf522SAndroid Build Coastguard Worker     }
194*288bf522SAndroid Build Coastguard Worker     result.push_back(entry->d_name);
195*288bf522SAndroid Build Coastguard Worker   }
196*288bf522SAndroid Build Coastguard Worker   closedir(dir);
197*288bf522SAndroid Build Coastguard Worker   return result;
198*288bf522SAndroid Build Coastguard Worker }
199*288bf522SAndroid Build Coastguard Worker 
GetSubDirs(const std::string & dirpath)200*288bf522SAndroid Build Coastguard Worker std::vector<std::string> GetSubDirs(const std::string& dirpath) {
201*288bf522SAndroid Build Coastguard Worker   std::vector<std::string> entries = GetEntriesInDir(dirpath);
202*288bf522SAndroid Build Coastguard Worker   std::vector<std::string> result;
203*288bf522SAndroid Build Coastguard Worker   for (size_t i = 0; i < entries.size(); ++i) {
204*288bf522SAndroid Build Coastguard Worker     if (IsDir(dirpath + OS_PATH_SEPARATOR + entries[i])) {
205*288bf522SAndroid Build Coastguard Worker       result.push_back(std::move(entries[i]));
206*288bf522SAndroid Build Coastguard Worker     }
207*288bf522SAndroid Build Coastguard Worker   }
208*288bf522SAndroid Build Coastguard Worker   return result;
209*288bf522SAndroid Build Coastguard Worker }
210*288bf522SAndroid Build Coastguard Worker 
IsDir(const std::string & dirpath)211*288bf522SAndroid Build Coastguard Worker bool IsDir(const std::string& dirpath) {
212*288bf522SAndroid Build Coastguard Worker   struct stat st;
213*288bf522SAndroid Build Coastguard Worker   if (stat(dirpath.c_str(), &st) == 0) {
214*288bf522SAndroid Build Coastguard Worker     if (S_ISDIR(st.st_mode)) {
215*288bf522SAndroid Build Coastguard Worker       return true;
216*288bf522SAndroid Build Coastguard Worker     }
217*288bf522SAndroid Build Coastguard Worker   }
218*288bf522SAndroid Build Coastguard Worker   return false;
219*288bf522SAndroid Build Coastguard Worker }
220*288bf522SAndroid Build Coastguard Worker 
IsRegularFile(const std::string & filename)221*288bf522SAndroid Build Coastguard Worker bool IsRegularFile(const std::string& filename) {
222*288bf522SAndroid Build Coastguard Worker   struct stat st;
223*288bf522SAndroid Build Coastguard Worker   if (stat(filename.c_str(), &st) == 0) {
224*288bf522SAndroid Build Coastguard Worker     if (S_ISREG(st.st_mode)) {
225*288bf522SAndroid Build Coastguard Worker       return true;
226*288bf522SAndroid Build Coastguard Worker     }
227*288bf522SAndroid Build Coastguard Worker   }
228*288bf522SAndroid Build Coastguard Worker   return false;
229*288bf522SAndroid Build Coastguard Worker }
230*288bf522SAndroid Build Coastguard Worker 
GetFileSize(const std::string & filename)231*288bf522SAndroid Build Coastguard Worker uint64_t GetFileSize(const std::string& filename) {
232*288bf522SAndroid Build Coastguard Worker   struct stat st;
233*288bf522SAndroid Build Coastguard Worker   if (stat(filename.c_str(), &st) == 0) {
234*288bf522SAndroid Build Coastguard Worker     return static_cast<uint64_t>(st.st_size);
235*288bf522SAndroid Build Coastguard Worker   }
236*288bf522SAndroid Build Coastguard Worker   return 0;
237*288bf522SAndroid Build Coastguard Worker }
238*288bf522SAndroid Build Coastguard Worker 
MkdirWithParents(const std::string & path)239*288bf522SAndroid Build Coastguard Worker bool MkdirWithParents(const std::string& path) {
240*288bf522SAndroid Build Coastguard Worker   size_t prev_end = 0;
241*288bf522SAndroid Build Coastguard Worker   while (prev_end < path.size()) {
242*288bf522SAndroid Build Coastguard Worker     size_t next_end = path.find('/', prev_end + 1);
243*288bf522SAndroid Build Coastguard Worker     if (next_end == std::string::npos) {
244*288bf522SAndroid Build Coastguard Worker       break;
245*288bf522SAndroid Build Coastguard Worker     }
246*288bf522SAndroid Build Coastguard Worker     std::string dir_path = path.substr(0, next_end);
247*288bf522SAndroid Build Coastguard Worker     if (!IsDir(dir_path)) {
248*288bf522SAndroid Build Coastguard Worker #if defined(_WIN32)
249*288bf522SAndroid Build Coastguard Worker       int ret = mkdir(dir_path.c_str());
250*288bf522SAndroid Build Coastguard Worker #else
251*288bf522SAndroid Build Coastguard Worker       int ret = mkdir(dir_path.c_str(), 0755);
252*288bf522SAndroid Build Coastguard Worker #endif
253*288bf522SAndroid Build Coastguard Worker       if (ret != 0) {
254*288bf522SAndroid Build Coastguard Worker         PLOG(ERROR) << "failed to create dir " << dir_path;
255*288bf522SAndroid Build Coastguard Worker         return false;
256*288bf522SAndroid Build Coastguard Worker       }
257*288bf522SAndroid Build Coastguard Worker     }
258*288bf522SAndroid Build Coastguard Worker     prev_end = next_end;
259*288bf522SAndroid Build Coastguard Worker   }
260*288bf522SAndroid Build Coastguard Worker   return true;
261*288bf522SAndroid Build Coastguard Worker }
262*288bf522SAndroid Build Coastguard Worker 
xz_alloc(ISzAllocPtr,size_t size)263*288bf522SAndroid Build Coastguard Worker static void* xz_alloc(ISzAllocPtr, size_t size) {
264*288bf522SAndroid Build Coastguard Worker   return malloc(size);
265*288bf522SAndroid Build Coastguard Worker }
266*288bf522SAndroid Build Coastguard Worker 
xz_free(ISzAllocPtr,void * address)267*288bf522SAndroid Build Coastguard Worker static void xz_free(ISzAllocPtr, void* address) {
268*288bf522SAndroid Build Coastguard Worker   free(address);
269*288bf522SAndroid Build Coastguard Worker }
270*288bf522SAndroid Build Coastguard Worker 
XzDecompress(const std::string & compressed_data,std::string * decompressed_data)271*288bf522SAndroid Build Coastguard Worker bool XzDecompress(const std::string& compressed_data, std::string* decompressed_data) {
272*288bf522SAndroid Build Coastguard Worker   ISzAlloc alloc;
273*288bf522SAndroid Build Coastguard Worker   CXzUnpacker state;
274*288bf522SAndroid Build Coastguard Worker   alloc.Alloc = xz_alloc;
275*288bf522SAndroid Build Coastguard Worker   alloc.Free = xz_free;
276*288bf522SAndroid Build Coastguard Worker   XzUnpacker_Construct(&state, &alloc);
277*288bf522SAndroid Build Coastguard Worker   CrcGenerateTable();
278*288bf522SAndroid Build Coastguard Worker   Crc64GenerateTable();
279*288bf522SAndroid Build Coastguard Worker   size_t src_offset = 0;
280*288bf522SAndroid Build Coastguard Worker   size_t dst_offset = 0;
281*288bf522SAndroid Build Coastguard Worker   std::string dst(compressed_data.size(), ' ');
282*288bf522SAndroid Build Coastguard Worker 
283*288bf522SAndroid Build Coastguard Worker   ECoderStatus status = CODER_STATUS_NOT_FINISHED;
284*288bf522SAndroid Build Coastguard Worker   while (status == CODER_STATUS_NOT_FINISHED) {
285*288bf522SAndroid Build Coastguard Worker     dst.resize(dst.size() * 2);
286*288bf522SAndroid Build Coastguard Worker     size_t src_remaining = compressed_data.size() - src_offset;
287*288bf522SAndroid Build Coastguard Worker     size_t dst_remaining = dst.size() - dst_offset;
288*288bf522SAndroid Build Coastguard Worker     int res = XzUnpacker_Code(&state, reinterpret_cast<Byte*>(&dst[dst_offset]), &dst_remaining,
289*288bf522SAndroid Build Coastguard Worker                               reinterpret_cast<const Byte*>(&compressed_data[src_offset]),
290*288bf522SAndroid Build Coastguard Worker                               &src_remaining, true, CODER_FINISH_ANY, &status);
291*288bf522SAndroid Build Coastguard Worker     if (res != SZ_OK) {
292*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "LZMA decompression failed with error " << res;
293*288bf522SAndroid Build Coastguard Worker       XzUnpacker_Free(&state);
294*288bf522SAndroid Build Coastguard Worker       return false;
295*288bf522SAndroid Build Coastguard Worker     }
296*288bf522SAndroid Build Coastguard Worker     src_offset += src_remaining;
297*288bf522SAndroid Build Coastguard Worker     dst_offset += dst_remaining;
298*288bf522SAndroid Build Coastguard Worker   }
299*288bf522SAndroid Build Coastguard Worker   XzUnpacker_Free(&state);
300*288bf522SAndroid Build Coastguard Worker   if (!XzUnpacker_IsStreamWasFinished(&state)) {
301*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "LZMA decompresstion failed due to incomplete stream";
302*288bf522SAndroid Build Coastguard Worker     return false;
303*288bf522SAndroid Build Coastguard Worker   }
304*288bf522SAndroid Build Coastguard Worker   dst.resize(dst_offset);
305*288bf522SAndroid Build Coastguard Worker   *decompressed_data = std::move(dst);
306*288bf522SAndroid Build Coastguard Worker   return true;
307*288bf522SAndroid Build Coastguard Worker }
308*288bf522SAndroid Build Coastguard Worker 
309*288bf522SAndroid Build Coastguard Worker static std::map<std::string, android::base::LogSeverity> log_severity_map = {
310*288bf522SAndroid Build Coastguard Worker     {"verbose", android::base::VERBOSE}, {"debug", android::base::DEBUG},
311*288bf522SAndroid Build Coastguard Worker     {"info", android::base::INFO},       {"warning", android::base::WARNING},
312*288bf522SAndroid Build Coastguard Worker     {"error", android::base::ERROR},     {"fatal", android::base::FATAL},
313*288bf522SAndroid Build Coastguard Worker };
GetLogSeverity(const std::string & name,android::base::LogSeverity * severity)314*288bf522SAndroid Build Coastguard Worker bool GetLogSeverity(const std::string& name, android::base::LogSeverity* severity) {
315*288bf522SAndroid Build Coastguard Worker   auto it = log_severity_map.find(name);
316*288bf522SAndroid Build Coastguard Worker   if (it != log_severity_map.end()) {
317*288bf522SAndroid Build Coastguard Worker     *severity = it->second;
318*288bf522SAndroid Build Coastguard Worker     return true;
319*288bf522SAndroid Build Coastguard Worker   }
320*288bf522SAndroid Build Coastguard Worker   return false;
321*288bf522SAndroid Build Coastguard Worker }
322*288bf522SAndroid Build Coastguard Worker 
GetLogSeverityName()323*288bf522SAndroid Build Coastguard Worker std::string GetLogSeverityName() {
324*288bf522SAndroid Build Coastguard Worker   android::base::LogSeverity severity = android::base::GetMinimumLogSeverity();
325*288bf522SAndroid Build Coastguard Worker   for (auto& pair : log_severity_map) {
326*288bf522SAndroid Build Coastguard Worker     if (severity == pair.second) {
327*288bf522SAndroid Build Coastguard Worker       return pair.first;
328*288bf522SAndroid Build Coastguard Worker     }
329*288bf522SAndroid Build Coastguard Worker   }
330*288bf522SAndroid Build Coastguard Worker   return "info";
331*288bf522SAndroid Build Coastguard Worker }
332*288bf522SAndroid Build Coastguard Worker 
IsRoot()333*288bf522SAndroid Build Coastguard Worker bool IsRoot() {
334*288bf522SAndroid Build Coastguard Worker   static int is_root = -1;
335*288bf522SAndroid Build Coastguard Worker   if (is_root == -1) {
336*288bf522SAndroid Build Coastguard Worker #if defined(__linux__)
337*288bf522SAndroid Build Coastguard Worker     is_root = (getuid() == 0) ? 1 : 0;
338*288bf522SAndroid Build Coastguard Worker #else
339*288bf522SAndroid Build Coastguard Worker     is_root = 0;
340*288bf522SAndroid Build Coastguard Worker #endif
341*288bf522SAndroid Build Coastguard Worker   }
342*288bf522SAndroid Build Coastguard Worker   return is_root == 1;
343*288bf522SAndroid Build Coastguard Worker }
344*288bf522SAndroid Build Coastguard Worker 
GetPageSize()345*288bf522SAndroid Build Coastguard Worker size_t GetPageSize() {
346*288bf522SAndroid Build Coastguard Worker #if defined(__linux__)
347*288bf522SAndroid Build Coastguard Worker   return sysconf(_SC_PAGE_SIZE);
348*288bf522SAndroid Build Coastguard Worker #else
349*288bf522SAndroid Build Coastguard Worker   return 4096;
350*288bf522SAndroid Build Coastguard Worker #endif
351*288bf522SAndroid Build Coastguard Worker }
352*288bf522SAndroid Build Coastguard Worker 
ConvertBytesToValue(const char * bytes,uint32_t size)353*288bf522SAndroid Build Coastguard Worker uint64_t ConvertBytesToValue(const char* bytes, uint32_t size) {
354*288bf522SAndroid Build Coastguard Worker   if (size > 8) {
355*288bf522SAndroid Build Coastguard Worker     LOG(FATAL) << "unexpected size " << size << " in ConvertBytesToValue";
356*288bf522SAndroid Build Coastguard Worker   }
357*288bf522SAndroid Build Coastguard Worker   uint64_t result = 0;
358*288bf522SAndroid Build Coastguard Worker   int shift = 0;
359*288bf522SAndroid Build Coastguard Worker   for (uint32_t i = 0; i < size; ++i) {
360*288bf522SAndroid Build Coastguard Worker     uint64_t tmp = static_cast<unsigned char>(bytes[i]);
361*288bf522SAndroid Build Coastguard Worker     result |= tmp << shift;
362*288bf522SAndroid Build Coastguard Worker     shift += 8;
363*288bf522SAndroid Build Coastguard Worker   }
364*288bf522SAndroid Build Coastguard Worker   return result;
365*288bf522SAndroid Build Coastguard Worker }
366*288bf522SAndroid Build Coastguard Worker 
SecondToTimeval(double time_in_sec)367*288bf522SAndroid Build Coastguard Worker timeval SecondToTimeval(double time_in_sec) {
368*288bf522SAndroid Build Coastguard Worker   timeval tv;
369*288bf522SAndroid Build Coastguard Worker   tv.tv_sec = static_cast<time_t>(time_in_sec);
370*288bf522SAndroid Build Coastguard Worker   tv.tv_usec = static_cast<int>((time_in_sec - tv.tv_sec) * 1000000);
371*288bf522SAndroid Build Coastguard Worker   return tv;
372*288bf522SAndroid Build Coastguard Worker }
373*288bf522SAndroid Build Coastguard Worker 
374*288bf522SAndroid Build Coastguard Worker constexpr int SIMPLEPERF_VERSION = 1;
375*288bf522SAndroid Build Coastguard Worker 
GetSimpleperfVersion()376*288bf522SAndroid Build Coastguard Worker std::string GetSimpleperfVersion() {
377*288bf522SAndroid Build Coastguard Worker   return StringPrintf("%d.build.%s", SIMPLEPERF_VERSION, android::build::GetBuildNumber().c_str());
378*288bf522SAndroid Build Coastguard Worker }
379*288bf522SAndroid Build Coastguard Worker 
380*288bf522SAndroid Build Coastguard Worker // Parse a line like: 0,1-3, 5, 7-8
GetCpusFromString(const std::string & s)381*288bf522SAndroid Build Coastguard Worker std::optional<std::set<int>> GetCpusFromString(const std::string& s) {
382*288bf522SAndroid Build Coastguard Worker   std::string str;
383*288bf522SAndroid Build Coastguard Worker   for (char c : s) {
384*288bf522SAndroid Build Coastguard Worker     if (!isspace(c)) {
385*288bf522SAndroid Build Coastguard Worker       str += c;
386*288bf522SAndroid Build Coastguard Worker     }
387*288bf522SAndroid Build Coastguard Worker   }
388*288bf522SAndroid Build Coastguard Worker   std::set<int> cpus;
389*288bf522SAndroid Build Coastguard Worker   int cpu1;
390*288bf522SAndroid Build Coastguard Worker   int cpu2;
391*288bf522SAndroid Build Coastguard Worker   for (const std::string& p : Split(str, ",")) {
392*288bf522SAndroid Build Coastguard Worker     size_t split_pos = p.find('-');
393*288bf522SAndroid Build Coastguard Worker     if (split_pos == std::string::npos) {
394*288bf522SAndroid Build Coastguard Worker       if (!ParseInt(p, &cpu1, 0)) {
395*288bf522SAndroid Build Coastguard Worker         LOG(ERROR) << "failed to parse cpu: " << p;
396*288bf522SAndroid Build Coastguard Worker         return std::nullopt;
397*288bf522SAndroid Build Coastguard Worker       }
398*288bf522SAndroid Build Coastguard Worker       cpus.insert(cpu1);
399*288bf522SAndroid Build Coastguard Worker     } else {
400*288bf522SAndroid Build Coastguard Worker       if (!ParseInt(p.substr(0, split_pos), &cpu1, 0) ||
401*288bf522SAndroid Build Coastguard Worker           !ParseInt(p.substr(split_pos + 1), &cpu2, 0) || cpu1 > cpu2) {
402*288bf522SAndroid Build Coastguard Worker         LOG(ERROR) << "failed to parse cpu: " << p;
403*288bf522SAndroid Build Coastguard Worker         return std::nullopt;
404*288bf522SAndroid Build Coastguard Worker       }
405*288bf522SAndroid Build Coastguard Worker       while (cpu1 <= cpu2) {
406*288bf522SAndroid Build Coastguard Worker         cpus.insert(cpu1++);
407*288bf522SAndroid Build Coastguard Worker       }
408*288bf522SAndroid Build Coastguard Worker     }
409*288bf522SAndroid Build Coastguard Worker   }
410*288bf522SAndroid Build Coastguard Worker   return cpus;
411*288bf522SAndroid Build Coastguard Worker }
412*288bf522SAndroid Build Coastguard Worker 
GetTidsFromString(const std::string & s,bool check_if_exists)413*288bf522SAndroid Build Coastguard Worker std::optional<std::set<pid_t>> GetTidsFromString(const std::string& s, bool check_if_exists) {
414*288bf522SAndroid Build Coastguard Worker   std::set<pid_t> tids;
415*288bf522SAndroid Build Coastguard Worker   for (const auto& p : Split(s, ",")) {
416*288bf522SAndroid Build Coastguard Worker     int tid;
417*288bf522SAndroid Build Coastguard Worker     if (!ParseInt(p.c_str(), &tid, 0)) {
418*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "Invalid tid '" << p << "'";
419*288bf522SAndroid Build Coastguard Worker       return std::nullopt;
420*288bf522SAndroid Build Coastguard Worker     }
421*288bf522SAndroid Build Coastguard Worker     if (check_if_exists && !IsDir(StringPrintf("/proc/%d", tid))) {
422*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "Non existing thread '" << tid << "'";
423*288bf522SAndroid Build Coastguard Worker       return std::nullopt;
424*288bf522SAndroid Build Coastguard Worker     }
425*288bf522SAndroid Build Coastguard Worker     tids.insert(tid);
426*288bf522SAndroid Build Coastguard Worker   }
427*288bf522SAndroid Build Coastguard Worker   return tids;
428*288bf522SAndroid Build Coastguard Worker }
429*288bf522SAndroid Build Coastguard Worker 
GetPidsFromStrings(const std::vector<std::string> & strs,bool check_if_exists,bool support_progress_name_regex)430*288bf522SAndroid Build Coastguard Worker std::optional<std::set<pid_t>> GetPidsFromStrings(const std::vector<std::string>& strs,
431*288bf522SAndroid Build Coastguard Worker                                                   bool check_if_exists,
432*288bf522SAndroid Build Coastguard Worker                                                   bool support_progress_name_regex) {
433*288bf522SAndroid Build Coastguard Worker   std::set<pid_t> pids;
434*288bf522SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<RegEx>> regs;
435*288bf522SAndroid Build Coastguard Worker   for (const auto& s : strs) {
436*288bf522SAndroid Build Coastguard Worker     for (const auto& p : Split(s, ",")) {
437*288bf522SAndroid Build Coastguard Worker       int pid;
438*288bf522SAndroid Build Coastguard Worker       if (ParseInt(p.c_str(), &pid, 0)) {
439*288bf522SAndroid Build Coastguard Worker         if (check_if_exists && !IsDir(StringPrintf("/proc/%d", pid))) {
440*288bf522SAndroid Build Coastguard Worker           LOG(ERROR) << "no process with pid " << pid;
441*288bf522SAndroid Build Coastguard Worker           return std::nullopt;
442*288bf522SAndroid Build Coastguard Worker         }
443*288bf522SAndroid Build Coastguard Worker         pids.insert(pid);
444*288bf522SAndroid Build Coastguard Worker       } else if (support_progress_name_regex) {
445*288bf522SAndroid Build Coastguard Worker         auto reg = RegEx::Create(p);
446*288bf522SAndroid Build Coastguard Worker         if (!reg) {
447*288bf522SAndroid Build Coastguard Worker           return std::nullopt;
448*288bf522SAndroid Build Coastguard Worker         }
449*288bf522SAndroid Build Coastguard Worker         regs.emplace_back(std::move(reg));
450*288bf522SAndroid Build Coastguard Worker       } else {
451*288bf522SAndroid Build Coastguard Worker         LOG(ERROR) << "invalid pid: " << p;
452*288bf522SAndroid Build Coastguard Worker         return std::nullopt;
453*288bf522SAndroid Build Coastguard Worker       }
454*288bf522SAndroid Build Coastguard Worker     }
455*288bf522SAndroid Build Coastguard Worker   }
456*288bf522SAndroid Build Coastguard Worker   if (!regs.empty()) {
457*288bf522SAndroid Build Coastguard Worker #if defined(__linux__)
458*288bf522SAndroid Build Coastguard Worker     for (pid_t pid : GetAllProcesses()) {
459*288bf522SAndroid Build Coastguard Worker       std::string process_name = GetCompleteProcessName(pid);
460*288bf522SAndroid Build Coastguard Worker       if (process_name.empty()) {
461*288bf522SAndroid Build Coastguard Worker         continue;
462*288bf522SAndroid Build Coastguard Worker       }
463*288bf522SAndroid Build Coastguard Worker       for (const auto& reg : regs) {
464*288bf522SAndroid Build Coastguard Worker         if (reg->Search(process_name)) {
465*288bf522SAndroid Build Coastguard Worker           pids.insert(pid);
466*288bf522SAndroid Build Coastguard Worker           break;
467*288bf522SAndroid Build Coastguard Worker         }
468*288bf522SAndroid Build Coastguard Worker       }
469*288bf522SAndroid Build Coastguard Worker     }
470*288bf522SAndroid Build Coastguard Worker #else   // defined(__linux__)
471*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "progress name regex isn't supported";
472*288bf522SAndroid Build Coastguard Worker     return std::nullopt;
473*288bf522SAndroid Build Coastguard Worker #endif  // defined(__linux__)
474*288bf522SAndroid Build Coastguard Worker   }
475*288bf522SAndroid Build Coastguard Worker   return pids;
476*288bf522SAndroid Build Coastguard Worker }
477*288bf522SAndroid Build Coastguard Worker 
SafeStrlen(const char * s,const char * end)478*288bf522SAndroid Build Coastguard Worker size_t SafeStrlen(const char* s, const char* end) {
479*288bf522SAndroid Build Coastguard Worker   const char* p = s;
480*288bf522SAndroid Build Coastguard Worker   while (p < end && *p != '\0') {
481*288bf522SAndroid Build Coastguard Worker     p++;
482*288bf522SAndroid Build Coastguard Worker   }
483*288bf522SAndroid Build Coastguard Worker   return p - s;
484*288bf522SAndroid Build Coastguard Worker }
485*288bf522SAndroid Build Coastguard Worker 
SafeAdd(uint64_t a,uint64_t b)486*288bf522SAndroid Build Coastguard Worker OverflowResult SafeAdd(uint64_t a, uint64_t b) {
487*288bf522SAndroid Build Coastguard Worker   OverflowResult result;
488*288bf522SAndroid Build Coastguard Worker   if (__builtin_add_overflow(a, b, &result.value)) {
489*288bf522SAndroid Build Coastguard Worker     result.overflow = true;
490*288bf522SAndroid Build Coastguard Worker   }
491*288bf522SAndroid Build Coastguard Worker   return result;
492*288bf522SAndroid Build Coastguard Worker }
493*288bf522SAndroid Build Coastguard Worker 
OverflowSafeAdd(uint64_t & dest,uint64_t add)494*288bf522SAndroid Build Coastguard Worker void OverflowSafeAdd(uint64_t& dest, uint64_t add) {
495*288bf522SAndroid Build Coastguard Worker   if (__builtin_add_overflow(dest, add, &dest)) {
496*288bf522SAndroid Build Coastguard Worker     LOG(WARNING) << "Branch count overflow happened.";
497*288bf522SAndroid Build Coastguard Worker     dest = UINT64_MAX;
498*288bf522SAndroid Build Coastguard Worker   }
499*288bf522SAndroid Build Coastguard Worker }
500*288bf522SAndroid Build Coastguard Worker 
501*288bf522SAndroid Build Coastguard Worker // Convert big numbers to human friendly mode. For example,
502*288bf522SAndroid Build Coastguard Worker // 1000000 will be converted to 1,000,000.
ReadableCount(uint64_t count)503*288bf522SAndroid Build Coastguard Worker std::string ReadableCount(uint64_t count) {
504*288bf522SAndroid Build Coastguard Worker   std::string s = std::to_string(count);
505*288bf522SAndroid Build Coastguard Worker   for (size_t i = s.size() - 1, j = 1; i > 0; --i, ++j) {
506*288bf522SAndroid Build Coastguard Worker     if (j == 3) {
507*288bf522SAndroid Build Coastguard Worker       s.insert(s.begin() + i, ',');
508*288bf522SAndroid Build Coastguard Worker       j = 0;
509*288bf522SAndroid Build Coastguard Worker     }
510*288bf522SAndroid Build Coastguard Worker   }
511*288bf522SAndroid Build Coastguard Worker   return s;
512*288bf522SAndroid Build Coastguard Worker }
513*288bf522SAndroid Build Coastguard Worker 
514*288bf522SAndroid Build Coastguard Worker // Convert bytes to human friendly mode.
ReadableBytes(uint64_t bytes)515*288bf522SAndroid Build Coastguard Worker std::string ReadableBytes(uint64_t bytes) {
516*288bf522SAndroid Build Coastguard Worker   if (bytes >= kMegabyte) {
517*288bf522SAndroid Build Coastguard Worker     return StringPrintf("%.2f MB", static_cast<double>(bytes) / kMegabyte);
518*288bf522SAndroid Build Coastguard Worker   }
519*288bf522SAndroid Build Coastguard Worker   if (bytes >= kKilobyte) {
520*288bf522SAndroid Build Coastguard Worker     return StringPrintf("%.2f KB", static_cast<double>(bytes) / kKilobyte);
521*288bf522SAndroid Build Coastguard Worker   }
522*288bf522SAndroid Build Coastguard Worker   return StringPrintf("%" PRIu64 " B", bytes);
523*288bf522SAndroid Build Coastguard Worker }
524*288bf522SAndroid Build Coastguard Worker 
525*288bf522SAndroid Build Coastguard Worker }  // namespace simpleperf
526