X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=simpleperf%2Fenvironment.cpp;h=5a8552a2c07ebc6f4530890005844e91553b7cf3;hb=beafc29feb2ad222d6c3e981ea307069ab23144e;hp=039eed5972b35b6f91668b25ae1f7ad09dfe1e40;hpb=74572c90416081921332b129cdb9bab1aea36d4a;p=android-x86%2Fsystem-extras.git diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp index 039eed59..5a8552a2 100644 --- a/simpleperf/environment.cpp +++ b/simpleperf/environment.cpp @@ -27,9 +27,14 @@ #include #include +#include #include #include +#if defined(__ANDROID__) +#include +#endif + #include "read_elf.h" #include "utils.h" @@ -140,37 +145,8 @@ bool ProcessKernelSymbols(const std::string& symbol_file, return false; } -static bool FindStartOfKernelSymbolCallback(const KernelSymbol& symbol, uint64_t* start_addr) { - if (symbol.module == nullptr) { - *start_addr = symbol.addr; - return true; - } - return false; -} - -static bool FindStartOfKernelSymbol(const std::string& symbol_file, uint64_t* start_addr) { - return ProcessKernelSymbols( - symbol_file, std::bind(&FindStartOfKernelSymbolCallback, std::placeholders::_1, start_addr)); -} - -static bool FindKernelFunctionSymbolCallback(const KernelSymbol& symbol, const std::string& name, - uint64_t* addr) { - if ((symbol.type == 'T' || symbol.type == 'W' || symbol.type == 'A') && - symbol.module == nullptr && name == symbol.name) { - *addr = symbol.addr; - return true; - } - return false; -} - -static bool FindKernelFunctionSymbol(const std::string& symbol_file, const std::string& name, - uint64_t* addr) { - return ProcessKernelSymbols( - symbol_file, std::bind(&FindKernelFunctionSymbolCallback, std::placeholders::_1, name, addr)); -} - -std::vector GetLoadedModules() { - std::vector result; +static std::vector GetLoadedModules() { + std::vector result; FILE* fp = fopen("/proc/modules", "re"); if (fp == nullptr) { // There is no /proc/modules on Android devices, so we don't print error if failed to open it. @@ -184,7 +160,7 @@ std::vector GetLoadedModules() { char name[reader.MaxLineSize()]; uint64_t addr; if (sscanf(line, "%s%*lu%*u%*s%*s 0x%" PRIx64, name, &addr) == 2) { - ModuleMmap map; + KernelMmap map; map.name = name; map.start_addr = addr; result.push_back(map); @@ -222,9 +198,9 @@ static void GetAllModuleFiles(const std::string& path, } } -static std::vector GetModulesInUse() { +static std::vector GetModulesInUse() { // TODO: There is no /proc/modules or /lib/modules on Android, find methods work on it. - std::vector module_mmaps = GetLoadedModules(); + std::vector module_mmaps = GetLoadedModules(); std::string linux_version = GetLinuxVersion(); std::string module_dirpath = "/lib/modules/" + linux_version + "/kernel"; std::unordered_map module_file_map; @@ -238,24 +214,23 @@ static std::vector GetModulesInUse() { return module_mmaps; } -bool GetKernelAndModuleMmaps(KernelMmap* kernel_mmap, std::vector* module_mmaps) { - if (!FindStartOfKernelSymbol("/proc/kallsyms", &kernel_mmap->start_addr)) { - LOG(DEBUG) << "call FindStartOfKernelSymbol() failed"; - return false; - } - if (!FindKernelFunctionSymbol("/proc/kallsyms", "_text", &kernel_mmap->pgoff)) { - LOG(DEBUG) << "call FindKernelFunctionSymbol() failed"; - return false; - } +void GetKernelAndModuleMmaps(KernelMmap* kernel_mmap, std::vector* module_mmaps) { kernel_mmap->name = DEFAULT_KERNEL_MMAP_NAME; + kernel_mmap->start_addr = 0; + kernel_mmap->filepath = kernel_mmap->name; *module_mmaps = GetModulesInUse(); + for (auto& map : *module_mmaps) { + if (map.filepath.empty()) { + map.filepath = "[" + map.name + "]"; + } + } + if (module_mmaps->size() == 0) { kernel_mmap->len = std::numeric_limits::max() - kernel_mmap->start_addr; } else { std::sort( module_mmaps->begin(), module_mmaps->end(), - [](const ModuleMmap& m1, const ModuleMmap& m2) { return m1.start_addr < m2.start_addr; }); - CHECK_LE(kernel_mmap->start_addr, (*module_mmaps)[0].start_addr); + [](const KernelMmap& m1, const KernelMmap& m2) { return m1.start_addr < m2.start_addr; }); // When not having enough privilege, all addresses are read as 0. if (kernel_mmap->start_addr == (*module_mmaps)[0].start_addr) { kernel_mmap->len = 0; @@ -273,7 +248,6 @@ bool GetKernelAndModuleMmaps(KernelMmap* kernel_mmap, std::vector* m module_mmaps->back().len = std::numeric_limits::max() - module_mmaps->back().start_addr; } - return true; } static bool ReadThreadNameAndTgid(const std::string& status_file, std::string* comm, pid_t* tgid) { @@ -305,9 +279,9 @@ static std::vector GetThreadsInProcess(pid_t pid) { std::string task_dirname = android::base::StringPrintf("/proc/%d/task", pid); std::vector subdirs; GetEntriesInDir(task_dirname, nullptr, &subdirs); - for (auto& name : subdirs) { + for (const auto& name : subdirs) { int tid; - if (!StringToPid(name, &tid)) { + if (!android::base::ParseInt(name.c_str(), &tid, 0)) { continue; } result.push_back(tid); @@ -341,7 +315,7 @@ bool GetThreadComms(std::vector* thread_comms) { GetEntriesInDir("/proc", nullptr, &subdirs); for (auto& name : subdirs) { int pid; - if (!StringToPid(name, &pid)) { + if (!android::base::ParseInt(name.c_str(), &pid, 0)) { continue; } if (!GetThreadComm(pid, thread_comms)) { @@ -396,9 +370,9 @@ bool GetModuleBuildId(const std::string& module_name, BuildId* build_id) { bool GetValidThreadsFromProcessString(const std::string& pid_str, std::set* tid_set) { std::vector strs = android::base::Split(pid_str, ","); - for (auto& s : strs) { + for (const auto& s : strs) { int pid; - if (!StringToPid(s, &pid)) { + if (!android::base::ParseInt(s.c_str(), &pid, 0)) { LOG(ERROR) << "Invalid pid '" << s << "'"; return false; } @@ -414,9 +388,9 @@ bool GetValidThreadsFromProcessString(const std::string& pid_str, std::set* tid_set) { std::vector strs = android::base::Split(tid_str, ","); - for (auto& s : strs) { + for (const auto& s : strs) { int tid; - if (!StringToPid(s, &tid)) { + if (!android::base::ParseInt(s.c_str(), &tid, 0)) { LOG(ERROR) << "Invalid tid '" << s << "'"; return false; } @@ -440,3 +414,66 @@ bool GetExecPath(std::string* exec_path) { *exec_path = path; return true; } + +/* + * perf event paranoia level: + * -1 - not paranoid at all + * 0 - disallow raw tracepoint access for unpriv + * 1 - disallow cpu events for unpriv + * 2 - disallow kernel profiling for unpriv + * 3 - disallow user profiling for unpriv + */ +static bool ReadPerfEventParanoid(int* value) { + std::string s; + if (!android::base::ReadFileToString("/proc/sys/kernel/perf_event_paranoid", &s)) { + PLOG(ERROR) << "failed to read /proc/sys/kernel/perf_event_paranoid"; + return false; + } + s = android::base::Trim(s); + if (!android::base::ParseInt(s.c_str(), value)) { + PLOG(ERROR) << "failed to parse /proc/sys/kernel/perf_event_paranoid: " << s; + return false; + } + return true; +} + +static const char* GetLimitLevelDescription(int limit_level) { + switch (limit_level) { + case -1: return "unlimited"; + case 0: return "disallowing raw tracepoint access for unpriv"; + case 1: return "disallowing cpu events for unpriv"; + case 2: return "disallowing kernel profiling for unpriv"; + case 3: return "disallowing user profiling for unpriv"; + default: return "unknown level"; + } +} + +bool CheckPerfEventLimit() { + // root is not limited by /proc/sys/kernel/perf_event_paranoid. + if (IsRoot()) { + return true; + } + int limit_level; + if (!ReadPerfEventParanoid(&limit_level)) { + return false; + } + if (limit_level <= 1) { + return true; + } +#if defined(__ANDROID__) + // Try to enable perf_event_paranoid by setprop security.perf_harden=0. + if (__system_property_set("security.perf_harden", "0") == 0) { + sleep(1); + if (ReadPerfEventParanoid(&limit_level) && limit_level <= 1) { + return true; + } + } + LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level + << ", " << GetLimitLevelDescription(limit_level) << "."; + LOG(WARNING) << "Try using `adb shell setprop security.perf_harden 0` to allow profiling."; +#else + LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level + << ", " << GetLimitLevelDescription(limit_level) << "."; +#endif + return true; +}