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 41 void OneTimeFreeAllocator::Clear() { 42 for (auto& p : v_) { 43 delete[] p; 44 } 45 v_.clear(); 46 cur_ = nullptr; 47 end_ = nullptr; 48 } 49 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 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 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 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 102 ArchiveHelper::~ArchiveHelper() { 103 CloseArchive(handle_); 104 } 105 106 bool ArchiveHelper::IterateEntries( 107 const std::function<bool(ZipEntry&, const std::string&)>& callback) { 108 void* iteration_cookie; 109 if (StartIteration(handle_, &iteration_cookie) < 0) { 110 LOG(ERROR) << "Failed to iterate " << filename_; 111 return false; 112 } 113 ZipEntry zentry; 114 std::string zname; 115 int result; 116 while ((result = Next(iteration_cookie, &zentry, &zname)) == 0) { 117 if (!callback(zentry, zname)) { 118 break; 119 } 120 } 121 EndIteration(iteration_cookie); 122 if (result == -2) { 123 LOG(ERROR) << "Failed to iterate " << filename_; 124 return false; 125 } 126 return true; 127 } 128 129 bool ArchiveHelper::FindEntry(const std::string& name, ZipEntry* entry) { 130 int result = ::FindEntry(handle_, name, entry); 131 if (result != 0) { 132 LOG(ERROR) << "Failed to find " << name << " in " << filename_; 133 return false; 134 } 135 return true; 136 } 137 138 bool ArchiveHelper::GetEntryData(ZipEntry& entry, std::vector<uint8_t>* data) { 139 data->resize(entry.uncompressed_length); 140 if (ExtractToMemory(handle_, &entry, data->data(), data->size()) != 0) { 141 LOG(ERROR) << "Failed to extract entry at " << entry.offset << " in " << filename_; 142 return false; 143 } 144 return true; 145 } 146 147 int ArchiveHelper::GetFd() { 148 return GetFileDescriptor(handle_); 149 } 150 151 void PrintIndented(size_t indent, const char* fmt, ...) { 152 va_list ap; 153 va_start(ap, fmt); 154 printf("%*s", static_cast<int>(indent * 2), ""); 155 vprintf(fmt, ap); 156 va_end(ap); 157 } 158 159 void FprintIndented(FILE* fp, size_t indent, const char* fmt, ...) { 160 va_list ap; 161 va_start(ap, fmt); 162 fprintf(fp, "%*s", static_cast<int>(indent * 2), ""); 163 vfprintf(fp, fmt, ap); 164 va_end(ap); 165 } 166 167 bool IsPowerOfTwo(uint64_t value) { 168 return (value != 0 && ((value & (value - 1)) == 0)); 169 } 170 171 std::vector<std::string> GetEntriesInDir(const std::string& dirpath) { 172 std::vector<std::string> result; 173 DIR* dir = opendir(dirpath.c_str()); 174 if (dir == nullptr) { 175 PLOG(DEBUG) << "can't open dir " << dirpath; 176 return result; 177 } 178 dirent* entry; 179 while ((entry = readdir(dir)) != nullptr) { 180 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { 181 continue; 182 } 183 result.push_back(entry->d_name); 184 } 185 closedir(dir); 186 return result; 187 } 188 189 std::vector<std::string> GetSubDirs(const std::string& dirpath) { 190 std::vector<std::string> entries = GetEntriesInDir(dirpath); 191 std::vector<std::string> result; 192 for (size_t i = 0; i < entries.size(); ++i) { 193 if (IsDir(dirpath + OS_PATH_SEPARATOR + entries[i])) { 194 result.push_back(std::move(entries[i])); 195 } 196 } 197 return result; 198 } 199 200 bool IsDir(const std::string& dirpath) { 201 struct stat st; 202 if (stat(dirpath.c_str(), &st) == 0) { 203 if (S_ISDIR(st.st_mode)) { 204 return true; 205 } 206 } 207 return false; 208 } 209 210 bool IsRegularFile(const std::string& filename) { 211 struct stat st; 212 if (stat(filename.c_str(), &st) == 0) { 213 if (S_ISREG(st.st_mode)) { 214 return true; 215 } 216 } 217 return false; 218 } 219 220 uint64_t GetFileSize(const std::string& filename) { 221 struct stat st; 222 if (stat(filename.c_str(), &st) == 0) { 223 return static_cast<uint64_t>(st.st_size); 224 } 225 return 0; 226 } 227 228 bool MkdirWithParents(const std::string& path) { 229 size_t prev_end = 0; 230 while (prev_end < path.size()) { 231 size_t next_end = path.find('/', prev_end + 1); 232 if (next_end == std::string::npos) { 233 break; 234 } 235 std::string dir_path = path.substr(0, next_end); 236 if (!IsDir(dir_path)) { 237 #if defined(_WIN32) 238 int ret = mkdir(dir_path.c_str()); 239 #else 240 int ret = mkdir(dir_path.c_str(), 0755); 241 #endif 242 if (ret != 0) { 243 PLOG(ERROR) << "failed to create dir " << dir_path; 244 return false; 245 } 246 } 247 prev_end = next_end; 248 } 249 return true; 250 } 251 252 static void* xz_alloc(ISzAllocPtr, size_t size) { 253 return malloc(size); 254 } 255 256 static void xz_free(ISzAllocPtr, void* address) { 257 free(address); 258 } 259 260 bool XzDecompress(const std::string& compressed_data, std::string* decompressed_data) { 261 ISzAlloc alloc; 262 CXzUnpacker state; 263 alloc.Alloc = xz_alloc; 264 alloc.Free = xz_free; 265 XzUnpacker_Construct(&state, &alloc); 266 CrcGenerateTable(); 267 Crc64GenerateTable(); 268 size_t src_offset = 0; 269 size_t dst_offset = 0; 270 std::string dst(compressed_data.size(), ' '); 271 272 ECoderStatus status = CODER_STATUS_NOT_FINISHED; 273 while (status == CODER_STATUS_NOT_FINISHED) { 274 dst.resize(dst.size() * 2); 275 size_t src_remaining = compressed_data.size() - src_offset; 276 size_t dst_remaining = dst.size() - dst_offset; 277 int res = XzUnpacker_Code(&state, reinterpret_cast<Byte*>(&dst[dst_offset]), &dst_remaining, 278 reinterpret_cast<const Byte*>(&compressed_data[src_offset]), 279 &src_remaining, true, CODER_FINISH_ANY, &status); 280 if (res != SZ_OK) { 281 LOG(ERROR) << "LZMA decompression failed with error " << res; 282 XzUnpacker_Free(&state); 283 return false; 284 } 285 src_offset += src_remaining; 286 dst_offset += dst_remaining; 287 } 288 XzUnpacker_Free(&state); 289 if (!XzUnpacker_IsStreamWasFinished(&state)) { 290 LOG(ERROR) << "LZMA decompresstion failed due to incomplete stream"; 291 return false; 292 } 293 dst.resize(dst_offset); 294 *decompressed_data = std::move(dst); 295 return true; 296 } 297 298 static std::map<std::string, android::base::LogSeverity> log_severity_map = { 299 {"verbose", android::base::VERBOSE}, 300 {"debug", android::base::DEBUG}, 301 {"info", android::base::INFO}, 302 {"warning", android::base::WARNING}, 303 {"error", android::base::ERROR}, 304 {"fatal", android::base::FATAL}, 305 }; 306 bool GetLogSeverity(const std::string& name, android::base::LogSeverity* severity) { 307 auto it = log_severity_map.find(name); 308 if (it != log_severity_map.end()) { 309 *severity = it->second; 310 return true; 311 } 312 return false; 313 } 314 315 std::string GetLogSeverityName() { 316 android::base::LogSeverity severity = android::base::GetMinimumLogSeverity(); 317 for (auto& pair : log_severity_map) { 318 if (severity == pair.second) { 319 return pair.first; 320 } 321 } 322 return "info"; 323 } 324 325 bool IsRoot() { 326 static int is_root = -1; 327 if (is_root == -1) { 328 #if defined(__linux__) 329 is_root = (getuid() == 0) ? 1 : 0; 330 #else 331 is_root = 0; 332 #endif 333 } 334 return is_root == 1; 335 } 336 337 bool ProcessKernelSymbols(std::string& symbol_data, 338 const std::function<bool(const KernelSymbol&)>& callback) { 339 char* p = &symbol_data[0]; 340 char* data_end = p + symbol_data.size(); 341 while (p < data_end) { 342 char* line_end = strchr(p, '\n'); 343 if (line_end != nullptr) { 344 *line_end = '\0'; 345 } 346 size_t line_size = (line_end != nullptr) ? (line_end - p) : (data_end - p); 347 // Parse line like: ffffffffa005c4e4 d __warned.41698 [libsas] 348 char name[line_size]; 349 char module[line_size]; 350 strcpy(module, ""); 351 352 KernelSymbol symbol; 353 int ret = sscanf(p, "%" PRIx64 " %c %s%s", &symbol.addr, &symbol.type, name, module); 354 if (line_end != nullptr) { 355 *line_end = '\n'; 356 p = line_end + 1; 357 } else { 358 p = data_end; 359 } 360 if (ret >= 3) { 361 symbol.name = name; 362 size_t module_len = strlen(module); 363 if (module_len > 2 && module[0] == '[' && module[module_len - 1] == ']') { 364 module[module_len - 1] = '\0'; 365 symbol.module = &module[1]; 366 } else { 367 symbol.module = nullptr; 368 } 369 370 if (callback(symbol)) { 371 return true; 372 } 373 } 374 } 375 return false; 376 } 377 378 size_t GetPageSize() { 379 #if defined(__linux__) 380 return sysconf(_SC_PAGE_SIZE); 381 #else 382 return 4096; 383 #endif 384 } 385 386 uint64_t ConvertBytesToValue(const char* bytes, uint32_t size) { 387 if (size > 8) { 388 LOG(FATAL) << "unexpected size " << size << " in ConvertBytesToValue"; 389 } 390 uint64_t result = 0; 391 int shift = 0; 392 for (uint32_t i = 0; i < size; ++i) { 393 uint64_t tmp = static_cast<unsigned char>(bytes[i]); 394 result |= tmp << shift; 395 shift += 8; 396 } 397 return result; 398 } 399 400 timeval SecondToTimeval(double time_in_sec) { 401 timeval tv; 402 tv.tv_sec = static_cast<time_t>(time_in_sec); 403 tv.tv_usec = static_cast<int>((time_in_sec - tv.tv_sec) * 1000000); 404 return tv; 405 } 406 407 constexpr int SIMPLEPERF_VERSION = 1; 408 409 std::string GetSimpleperfVersion() { 410 return android::base::StringPrintf("%d.build.%s", SIMPLEPERF_VERSION, 411 android::build::GetBuildNumber().c_str()); 412 } 413 414 std::vector<int> GetCpusFromString(const std::string& s) { 415 std::set<int> cpu_set; 416 bool have_dash = false; 417 const char* p = s.c_str(); 418 char* endp; 419 int last_cpu; 420 int cpu; 421 // Parse line like: 0,1-3, 5, 7-8 422 while ((cpu = static_cast<int>(strtol(p, &endp, 10))) != 0 || endp != p) { 423 if (have_dash && !cpu_set.empty()) { 424 for (int t = last_cpu + 1; t < cpu; ++t) { 425 cpu_set.insert(t); 426 } 427 } 428 have_dash = false; 429 cpu_set.insert(cpu); 430 last_cpu = cpu; 431 p = endp; 432 while (!isdigit(*p) && *p != '\0') { 433 if (*p == '-') { 434 have_dash = true; 435 } 436 ++p; 437 } 438 } 439 return std::vector<int>(cpu_set.begin(), cpu_set.end()); 440 } 441