1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "utils.h"
18
19 #include <dirent.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <inttypes.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27
28 #include <algorithm>
29 #include <map>
30 #include <string>
31
32 #include <android-base/file.h>
33 #include <android-base/logging.h>
34 #include <android-base/stringprintf.h>
35 #include <build/version.h>
36
37 #include <7zCrc.h>
38 #include <Xz.h>
39 #include <XzCrc64.h>
40
Clear()41 void OneTimeFreeAllocator::Clear() {
42 for (auto& p : v_) {
43 delete[] p;
44 }
45 v_.clear();
46 cur_ = nullptr;
47 end_ = nullptr;
48 }
49
AllocateString(std::string_view s)50 const char* OneTimeFreeAllocator::AllocateString(std::string_view s) {
51 size_t size = s.size() + 1;
52 if (cur_ + size > end_) {
53 size_t alloc_size = std::max(size, unit_size_);
54 char* p = new char[alloc_size];
55 v_.push_back(p);
56 cur_ = p;
57 end_ = p + alloc_size;
58 }
59 strcpy(cur_, s.data());
60 const char* result = cur_;
61 cur_ += size;
62 return result;
63 }
64
65
OpenReadOnly(const std::string & filename)66 android::base::unique_fd FileHelper::OpenReadOnly(const std::string& filename) {
67 int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY | O_BINARY));
68 return android::base::unique_fd(fd);
69 }
70
OpenWriteOnly(const std::string & filename)71 android::base::unique_fd FileHelper::OpenWriteOnly(const std::string& filename) {
72 int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), O_WRONLY | O_BINARY | O_CREAT, 0644));
73 return android::base::unique_fd(fd);
74 }
75
CreateInstance(const std::string & filename)76 std::unique_ptr<ArchiveHelper> ArchiveHelper::CreateInstance(const std::string& filename) {
77 android::base::unique_fd fd = FileHelper::OpenReadOnly(filename);
78 if (fd == -1) {
79 return nullptr;
80 }
81 // Simpleperf relies on ArchiveHelper to check if a file is zip file. We expect much more elf
82 // files than zip files in a process map. In order to detect invalid zip files fast, we add a
83 // check of magic number here. Note that OpenArchiveFd() detects invalid zip files in a thorough
84 // way, but it usually needs reading at least 64K file data.
85 static const char zip_preamble[] = {0x50, 0x4b, 0x03, 0x04 };
86 char buf[4];
87 if (!android::base::ReadFully(fd, buf, 4) || memcmp(buf, zip_preamble, 4) != 0) {
88 return nullptr;
89 }
90 if (lseek(fd, 0, SEEK_SET) == -1) {
91 return nullptr;
92 }
93 ZipArchiveHandle handle;
94 int result = OpenArchiveFd(fd.release(), filename.c_str(), &handle);
95 if (result != 0) {
96 LOG(ERROR) << "Failed to open archive " << filename << ": " << ErrorCodeString(result);
97 return nullptr;
98 }
99 return std::unique_ptr<ArchiveHelper>(new ArchiveHelper(handle, filename));
100 }
101
~ArchiveHelper()102 ArchiveHelper::~ArchiveHelper() {
103 CloseArchive(handle_);
104 }
105
IterateEntries(const std::function<bool (ZipEntry &,const std::string &)> & callback)106 bool ArchiveHelper::IterateEntries(
107 const std::function<bool(ZipEntry&, const std::string&)>& callback) {
108 void* iteration_cookie;
109 if (StartIteration(handle_, &iteration_cookie, nullptr, nullptr) < 0) {
110 LOG(ERROR) << "Failed to iterate " << filename_;
111 return false;
112 }
113 ZipEntry zentry;
114 ZipString zname;
115 int result;
116 while ((result = Next(iteration_cookie, &zentry, &zname)) == 0) {
117 std::string name(zname.name, zname.name + zname.name_length);
118 if (!callback(zentry, name)) {
119 break;
120 }
121 }
122 EndIteration(iteration_cookie);
123 if (result == -2) {
124 LOG(ERROR) << "Failed to iterate " << filename_;
125 return false;
126 }
127 return true;
128 }
129
FindEntry(const std::string & name,ZipEntry * entry)130 bool ArchiveHelper::FindEntry(const std::string& name, ZipEntry* entry) {
131 int result = ::FindEntry(handle_, ZipString(name.c_str()), entry);
132 if (result != 0) {
133 LOG(ERROR) << "Failed to find " << name << " in " << filename_;
134 return false;
135 }
136 return true;
137 }
138
GetEntryData(ZipEntry & entry,std::vector<uint8_t> * data)139 bool ArchiveHelper::GetEntryData(ZipEntry& entry, std::vector<uint8_t>* data) {
140 data->resize(entry.uncompressed_length);
141 if (ExtractToMemory(handle_, &entry, data->data(), data->size()) != 0) {
142 LOG(ERROR) << "Failed to extract entry at " << entry.offset << " in " << filename_;
143 return false;
144 }
145 return true;
146 }
147
GetFd()148 int ArchiveHelper::GetFd() {
149 return GetFileDescriptor(handle_);
150 }
151
PrintIndented(size_t indent,const char * fmt,...)152 void PrintIndented(size_t indent, const char* fmt, ...) {
153 va_list ap;
154 va_start(ap, fmt);
155 printf("%*s", static_cast<int>(indent * 2), "");
156 vprintf(fmt, ap);
157 va_end(ap);
158 }
159
FprintIndented(FILE * fp,size_t indent,const char * fmt,...)160 void FprintIndented(FILE* fp, size_t indent, const char* fmt, ...) {
161 va_list ap;
162 va_start(ap, fmt);
163 fprintf(fp, "%*s", static_cast<int>(indent * 2), "");
164 vfprintf(fp, fmt, ap);
165 va_end(ap);
166 }
167
IsPowerOfTwo(uint64_t value)168 bool IsPowerOfTwo(uint64_t value) {
169 return (value != 0 && ((value & (value - 1)) == 0));
170 }
171
GetEntriesInDir(const std::string & dirpath)172 std::vector<std::string> GetEntriesInDir(const std::string& dirpath) {
173 std::vector<std::string> result;
174 DIR* dir = opendir(dirpath.c_str());
175 if (dir == nullptr) {
176 PLOG(DEBUG) << "can't open dir " << dirpath;
177 return result;
178 }
179 dirent* entry;
180 while ((entry = readdir(dir)) != nullptr) {
181 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
182 continue;
183 }
184 result.push_back(entry->d_name);
185 }
186 closedir(dir);
187 return result;
188 }
189
GetSubDirs(const std::string & dirpath)190 std::vector<std::string> GetSubDirs(const std::string& dirpath) {
191 std::vector<std::string> entries = GetEntriesInDir(dirpath);
192 std::vector<std::string> result;
193 for (size_t i = 0; i < entries.size(); ++i) {
194 if (IsDir(dirpath + OS_PATH_SEPARATOR + entries[i])) {
195 result.push_back(std::move(entries[i]));
196 }
197 }
198 return result;
199 }
200
IsDir(const std::string & dirpath)201 bool IsDir(const std::string& dirpath) {
202 struct stat st;
203 if (stat(dirpath.c_str(), &st) == 0) {
204 if (S_ISDIR(st.st_mode)) {
205 return true;
206 }
207 }
208 return false;
209 }
210
IsRegularFile(const std::string & filename)211 bool IsRegularFile(const std::string& filename) {
212 struct stat st;
213 if (stat(filename.c_str(), &st) == 0) {
214 if (S_ISREG(st.st_mode)) {
215 return true;
216 }
217 }
218 return false;
219 }
220
GetFileSize(const std::string & filename)221 uint64_t GetFileSize(const std::string& filename) {
222 struct stat st;
223 if (stat(filename.c_str(), &st) == 0) {
224 return static_cast<uint64_t>(st.st_size);
225 }
226 return 0;
227 }
228
MkdirWithParents(const std::string & path)229 bool MkdirWithParents(const std::string& path) {
230 size_t prev_end = 0;
231 while (prev_end < path.size()) {
232 size_t next_end = path.find('/', prev_end + 1);
233 if (next_end == std::string::npos) {
234 break;
235 }
236 std::string dir_path = path.substr(0, next_end);
237 if (!IsDir(dir_path)) {
238 #if defined(_WIN32)
239 int ret = mkdir(dir_path.c_str());
240 #else
241 int ret = mkdir(dir_path.c_str(), 0755);
242 #endif
243 if (ret != 0) {
244 PLOG(ERROR) << "failed to create dir " << dir_path;
245 return false;
246 }
247 }
248 prev_end = next_end;
249 }
250 return true;
251 }
252
xz_alloc(ISzAllocPtr,size_t size)253 static void* xz_alloc(ISzAllocPtr, size_t size) {
254 return malloc(size);
255 }
256
xz_free(ISzAllocPtr,void * address)257 static void xz_free(ISzAllocPtr, void* address) {
258 free(address);
259 }
260
XzDecompress(const std::string & compressed_data,std::string * decompressed_data)261 bool XzDecompress(const std::string& compressed_data, std::string* decompressed_data) {
262 ISzAlloc alloc;
263 CXzUnpacker state;
264 alloc.Alloc = xz_alloc;
265 alloc.Free = xz_free;
266 XzUnpacker_Construct(&state, &alloc);
267 CrcGenerateTable();
268 Crc64GenerateTable();
269 size_t src_offset = 0;
270 size_t dst_offset = 0;
271 std::string dst(compressed_data.size(), ' ');
272
273 ECoderStatus status = CODER_STATUS_NOT_FINISHED;
274 while (status == CODER_STATUS_NOT_FINISHED) {
275 dst.resize(dst.size() * 2);
276 size_t src_remaining = compressed_data.size() - src_offset;
277 size_t dst_remaining = dst.size() - dst_offset;
278 int res = XzUnpacker_Code(&state, reinterpret_cast<Byte*>(&dst[dst_offset]), &dst_remaining,
279 reinterpret_cast<const Byte*>(&compressed_data[src_offset]),
280 &src_remaining, true, CODER_FINISH_ANY, &status);
281 if (res != SZ_OK) {
282 LOG(ERROR) << "LZMA decompression failed with error " << res;
283 XzUnpacker_Free(&state);
284 return false;
285 }
286 src_offset += src_remaining;
287 dst_offset += dst_remaining;
288 }
289 XzUnpacker_Free(&state);
290 if (!XzUnpacker_IsStreamWasFinished(&state)) {
291 LOG(ERROR) << "LZMA decompresstion failed due to incomplete stream";
292 return false;
293 }
294 dst.resize(dst_offset);
295 *decompressed_data = std::move(dst);
296 return true;
297 }
298
299 static std::map<std::string, android::base::LogSeverity> log_severity_map = {
300 {"verbose", android::base::VERBOSE},
301 {"debug", android::base::DEBUG},
302 {"info", android::base::INFO},
303 {"warning", android::base::WARNING},
304 {"error", android::base::ERROR},
305 {"fatal", android::base::FATAL},
306 };
GetLogSeverity(const std::string & name,android::base::LogSeverity * severity)307 bool GetLogSeverity(const std::string& name, android::base::LogSeverity* severity) {
308 auto it = log_severity_map.find(name);
309 if (it != log_severity_map.end()) {
310 *severity = it->second;
311 return true;
312 }
313 return false;
314 }
315
GetLogSeverityName()316 std::string GetLogSeverityName() {
317 android::base::LogSeverity severity = android::base::GetMinimumLogSeverity();
318 for (auto& pair : log_severity_map) {
319 if (severity == pair.second) {
320 return pair.first;
321 }
322 }
323 return "info";
324 }
325
IsRoot()326 bool IsRoot() {
327 static int is_root = -1;
328 if (is_root == -1) {
329 #if defined(__linux__)
330 is_root = (getuid() == 0) ? 1 : 0;
331 #else
332 is_root = 0;
333 #endif
334 }
335 return is_root == 1;
336 }
337
ProcessKernelSymbols(std::string & symbol_data,const std::function<bool (const KernelSymbol &)> & callback)338 bool ProcessKernelSymbols(std::string& symbol_data,
339 const std::function<bool(const KernelSymbol&)>& callback) {
340 char* p = &symbol_data[0];
341 char* data_end = p + symbol_data.size();
342 while (p < data_end) {
343 char* line_end = strchr(p, '\n');
344 if (line_end != nullptr) {
345 *line_end = '\0';
346 }
347 size_t line_size = (line_end != nullptr) ? (line_end - p) : (data_end - p);
348 // Parse line like: ffffffffa005c4e4 d __warned.41698 [libsas]
349 char name[line_size];
350 char module[line_size];
351 strcpy(module, "");
352
353 KernelSymbol symbol;
354 int ret = sscanf(p, "%" PRIx64 " %c %s%s", &symbol.addr, &symbol.type, name, module);
355 if (line_end != nullptr) {
356 *line_end = '\n';
357 p = line_end + 1;
358 } else {
359 p = data_end;
360 }
361 if (ret >= 3) {
362 symbol.name = name;
363 size_t module_len = strlen(module);
364 if (module_len > 2 && module[0] == '[' && module[module_len - 1] == ']') {
365 module[module_len - 1] = '\0';
366 symbol.module = &module[1];
367 } else {
368 symbol.module = nullptr;
369 }
370
371 if (callback(symbol)) {
372 return true;
373 }
374 }
375 }
376 return false;
377 }
378
GetPageSize()379 size_t GetPageSize() {
380 #if defined(__linux__)
381 return sysconf(_SC_PAGE_SIZE);
382 #else
383 return 4096;
384 #endif
385 }
386
ConvertBytesToValue(const char * bytes,uint32_t size)387 uint64_t ConvertBytesToValue(const char* bytes, uint32_t size) {
388 if (size > 8) {
389 LOG(FATAL) << "unexpected size " << size << " in ConvertBytesToValue";
390 }
391 uint64_t result = 0;
392 int shift = 0;
393 for (uint32_t i = 0; i < size; ++i) {
394 uint64_t tmp = static_cast<unsigned char>(bytes[i]);
395 result |= tmp << shift;
396 shift += 8;
397 }
398 return result;
399 }
400
SecondToTimeval(double time_in_sec)401 timeval SecondToTimeval(double time_in_sec) {
402 timeval tv;
403 tv.tv_sec = static_cast<time_t>(time_in_sec);
404 tv.tv_usec = static_cast<int>((time_in_sec - tv.tv_sec) * 1000000);
405 return tv;
406 }
407
408 constexpr int SIMPLEPERF_VERSION = 1;
409
GetSimpleperfVersion()410 std::string GetSimpleperfVersion() {
411 return android::base::StringPrintf("%d.build.%s", SIMPLEPERF_VERSION,
412 android::build::GetBuildNumber().c_str());
413 }
414