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 36 #include <7zCrc.h> 37 #include <Xz.h> 38 #include <XzCrc64.h> 39 40 void OneTimeFreeAllocator::Clear() { 41 for (auto& p : v_) { 42 delete[] p; 43 } 44 v_.clear(); 45 cur_ = nullptr; 46 end_ = nullptr; 47 } 48 49 const char* OneTimeFreeAllocator::AllocateString(const std::string& s) { 50 size_t size = s.size() + 1; 51 if (cur_ + size > end_) { 52 size_t alloc_size = std::max(size, unit_size_); 53 char* p = new char[alloc_size]; 54 v_.push_back(p); 55 cur_ = p; 56 end_ = p + alloc_size; 57 } 58 strcpy(cur_, s.c_str()); 59 const char* result = cur_; 60 cur_ += size; 61 return result; 62 } 63 64 65 FileHelper FileHelper::OpenReadOnly(const std::string& filename) { 66 int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY | O_BINARY)); 67 return FileHelper(fd); 68 } 69 70 FileHelper FileHelper::OpenWriteOnly(const std::string& filename) { 71 int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), O_WRONLY | O_BINARY | O_CREAT, 0644)); 72 return FileHelper(fd); 73 } 74 75 FileHelper::~FileHelper() { 76 if (fd_ != -1) { 77 close(fd_); 78 } 79 } 80 81 ArchiveHelper::ArchiveHelper(int fd, const std::string& debug_filename) : valid_(false) { 82 int rc = OpenArchiveFd(fd, "", &handle_, false); 83 if (rc == 0) { 84 valid_ = true; 85 } else { 86 LOG(ERROR) << "Failed to open archive " << debug_filename << ": " << ErrorCodeString(rc); 87 } 88 } 89 90 ArchiveHelper::~ArchiveHelper() { 91 if (valid_) { 92 CloseArchive(handle_); 93 } 94 } 95 96 void PrintIndented(size_t indent, const char* fmt, ...) { 97 va_list ap; 98 va_start(ap, fmt); 99 printf("%*s", static_cast<int>(indent * 2), ""); 100 vprintf(fmt, ap); 101 va_end(ap); 102 } 103 104 void FprintIndented(FILE* fp, size_t indent, const char* fmt, ...) { 105 va_list ap; 106 va_start(ap, fmt); 107 fprintf(fp, "%*s", static_cast<int>(indent * 2), ""); 108 vfprintf(fp, fmt, ap); 109 va_end(ap); 110 } 111 112 bool IsPowerOfTwo(uint64_t value) { 113 return (value != 0 && ((value & (value - 1)) == 0)); 114 } 115 116 std::vector<std::string> GetEntriesInDir(const std::string& dirpath) { 117 std::vector<std::string> result; 118 DIR* dir = opendir(dirpath.c_str()); 119 if (dir == nullptr) { 120 PLOG(DEBUG) << "can't open dir " << dirpath; 121 return result; 122 } 123 dirent* entry; 124 while ((entry = readdir(dir)) != nullptr) { 125 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { 126 continue; 127 } 128 result.push_back(entry->d_name); 129 } 130 closedir(dir); 131 return result; 132 } 133 134 std::vector<std::string> GetSubDirs(const std::string& dirpath) { 135 std::vector<std::string> entries = GetEntriesInDir(dirpath); 136 std::vector<std::string> result; 137 for (size_t i = 0; i < entries.size(); ++i) { 138 if (IsDir(dirpath + "/" + entries[i])) { 139 result.push_back(std::move(entries[i])); 140 } 141 } 142 return result; 143 } 144 145 bool IsDir(const std::string& dirpath) { 146 struct stat st; 147 if (stat(dirpath.c_str(), &st) == 0) { 148 if (S_ISDIR(st.st_mode)) { 149 return true; 150 } 151 } 152 return false; 153 } 154 155 bool IsRegularFile(const std::string& filename) { 156 struct stat st; 157 if (stat(filename.c_str(), &st) == 0) { 158 if (S_ISREG(st.st_mode)) { 159 return true; 160 } 161 } 162 return false; 163 } 164 165 uint64_t GetFileSize(const std::string& filename) { 166 struct stat st; 167 if (stat(filename.c_str(), &st) == 0) { 168 return static_cast<uint64_t>(st.st_size); 169 } 170 return 0; 171 } 172 173 bool MkdirWithParents(const std::string& path) { 174 size_t prev_end = 0; 175 while (prev_end < path.size()) { 176 size_t next_end = path.find('/', prev_end + 1); 177 if (next_end == std::string::npos) { 178 break; 179 } 180 std::string dir_path = path.substr(0, next_end); 181 if (!IsDir(dir_path)) { 182 #if defined(_WIN32) 183 int ret = mkdir(dir_path.c_str()); 184 #else 185 int ret = mkdir(dir_path.c_str(), 0755); 186 #endif 187 if (ret != 0) { 188 PLOG(ERROR) << "failed to create dir " << dir_path; 189 return false; 190 } 191 } 192 prev_end = next_end; 193 } 194 return true; 195 } 196 197 static void* xz_alloc(void*, size_t size) { 198 return malloc(size); 199 } 200 201 static void xz_free(void*, void* address) { 202 free(address); 203 } 204 205 bool XzDecompress(const std::string& compressed_data, std::string* decompressed_data) { 206 ISzAlloc alloc; 207 CXzUnpacker state; 208 alloc.Alloc = xz_alloc; 209 alloc.Free = xz_free; 210 XzUnpacker_Construct(&state, &alloc); 211 CrcGenerateTable(); 212 Crc64GenerateTable(); 213 size_t src_offset = 0; 214 size_t dst_offset = 0; 215 std::string dst(compressed_data.size(), ' '); 216 217 ECoderStatus status = CODER_STATUS_NOT_FINISHED; 218 while (status == CODER_STATUS_NOT_FINISHED) { 219 dst.resize(dst.size() * 2); 220 size_t src_remaining = compressed_data.size() - src_offset; 221 size_t dst_remaining = dst.size() - dst_offset; 222 int res = XzUnpacker_Code(&state, reinterpret_cast<Byte*>(&dst[dst_offset]), &dst_remaining, 223 reinterpret_cast<const Byte*>(&compressed_data[src_offset]), 224 &src_remaining, CODER_FINISH_ANY, &status); 225 if (res != SZ_OK) { 226 LOG(ERROR) << "LZMA decompression failed with error " << res; 227 XzUnpacker_Free(&state); 228 return false; 229 } 230 src_offset += src_remaining; 231 dst_offset += dst_remaining; 232 } 233 XzUnpacker_Free(&state); 234 if (!XzUnpacker_IsStreamWasFinished(&state)) { 235 LOG(ERROR) << "LZMA decompresstion failed due to incomplete stream"; 236 return false; 237 } 238 dst.resize(dst_offset); 239 *decompressed_data = std::move(dst); 240 return true; 241 } 242 243 static std::map<std::string, android::base::LogSeverity> log_severity_map = { 244 {"verbose", android::base::VERBOSE}, 245 {"debug", android::base::DEBUG}, 246 {"info", android::base::INFO}, 247 {"warning", android::base::WARNING}, 248 {"error", android::base::ERROR}, 249 {"fatal", android::base::FATAL}, 250 }; 251 bool GetLogSeverity(const std::string& name, android::base::LogSeverity* severity) { 252 auto it = log_severity_map.find(name); 253 if (it != log_severity_map.end()) { 254 *severity = it->second; 255 return true; 256 } 257 return false; 258 } 259 260 std::string GetLogSeverityName() { 261 android::base::LogSeverity severity = android::base::GetMinimumLogSeverity(); 262 for (auto& pair : log_severity_map) { 263 if (severity == pair.second) { 264 return pair.first; 265 } 266 } 267 return "info"; 268 } 269 270 bool IsRoot() { 271 static int is_root = -1; 272 if (is_root == -1) { 273 #if defined(__linux__) 274 is_root = (getuid() == 0) ? 1 : 0; 275 #else 276 is_root = 0; 277 #endif 278 } 279 return is_root == 1; 280 } 281 282 bool ProcessKernelSymbols(std::string& symbol_data, 283 const std::function<bool(const KernelSymbol&)>& callback) { 284 char* p = &symbol_data[0]; 285 char* data_end = p + symbol_data.size(); 286 while (p < data_end) { 287 char* line_end = strchr(p, '\n'); 288 if (line_end != nullptr) { 289 *line_end = '\0'; 290 } 291 size_t line_size = (line_end != nullptr) ? (line_end - p) : (data_end - p); 292 // Parse line like: ffffffffa005c4e4 d __warned.41698 [libsas] 293 char name[line_size]; 294 char module[line_size]; 295 strcpy(module, ""); 296 297 KernelSymbol symbol; 298 int ret = sscanf(p, "%" PRIx64 " %c %s%s", &symbol.addr, &symbol.type, name, module); 299 if (line_end != nullptr) { 300 *line_end = '\n'; 301 p = line_end + 1; 302 } else { 303 p = data_end; 304 } 305 if (ret >= 3) { 306 symbol.name = name; 307 size_t module_len = strlen(module); 308 if (module_len > 2 && module[0] == '[' && module[module_len - 1] == ']') { 309 module[module_len - 1] = '\0'; 310 symbol.module = &module[1]; 311 } else { 312 symbol.module = nullptr; 313 } 314 315 if (callback(symbol)) { 316 return true; 317 } 318 } 319 } 320 return false; 321 } 322 323 size_t GetPageSize() { 324 #if defined(__linux__) 325 return sysconf(_SC_PAGE_SIZE); 326 #else 327 return 4096; 328 #endif 329 } 330 331 uint64_t ConvertBytesToValue(const char* bytes, uint32_t size) { 332 if (size > 8) { 333 LOG(FATAL) << "unexpected size " << size << " in ConvertBytesToValue"; 334 } 335 uint64_t result = 0; 336 int shift = 0; 337 for (uint32_t i = 0; i < size; ++i) { 338 uint64_t tmp = static_cast<unsigned char>(bytes[i]); 339 result |= tmp << shift; 340 shift += 8; 341 } 342 return result; 343 } 344 345 timeval SecondToTimeval(double time_in_sec) { 346 timeval tv; 347 tv.tv_sec = static_cast<time_t>(time_in_sec); 348 tv.tv_usec = static_cast<int>((time_in_sec - tv.tv_sec) * 1000000); 349 return tv; 350 } 351 352 constexpr int SIMPLEPERF_VERSION = 1; 353 354 std::string GetSimpleperfVersion() { 355 return android::base::StringPrintf("%d.%s", SIMPLEPERF_VERSION, SIMPLEPERF_REVISION); 356 } 357