diff options
-rw-r--r-- | simpleperf/cmd_list.cpp | 16 | ||||
-rw-r--r-- | simpleperf/cmd_record.cpp | 4 | ||||
-rw-r--r-- | simpleperf/cmd_stat.cpp | 4 | ||||
-rw-r--r-- | simpleperf/environment.cpp | 63 | ||||
-rw-r--r-- | simpleperf/environment.h | 2 |
5 files changed, 86 insertions, 3 deletions
diff --git a/simpleperf/cmd_list.cpp b/simpleperf/cmd_list.cpp index b6bf817c..273a8037 100644 --- a/simpleperf/cmd_list.cpp +++ b/simpleperf/cmd_list.cpp @@ -22,6 +22,7 @@ #include <android-base/logging.h> #include "command.h" +#include "environment.h" #include "event_attr.h" #include "event_fd.h" #include "event_type.h" @@ -30,9 +31,14 @@ static void PrintEventTypesOfType(uint32_t type, const std::string& type_name, const std::vector<EventType>& event_types) { printf("List of %s:\n", type_name.c_str()); for (auto& event_type : event_types) { - if (event_type.type == type && - IsEventAttrSupportedByKernel(CreateDefaultPerfEventAttr(event_type))) { - printf(" %s\n", event_type.name.c_str()); + if (event_type.type == type) { + perf_event_attr attr = CreateDefaultPerfEventAttr(event_type); + // Exclude kernel to list supported events even when + // /proc/sys/kernel/perf_event_paranoid is 2. + attr.exclude_kernel = 1; + if (IsEventAttrSupportedByKernel(attr)) { + printf(" %s\n", event_type.name.c_str()); + } } } printf("\n"); @@ -50,6 +56,10 @@ class ListCommand : public Command { }; bool ListCommand::Run(const std::vector<std::string>& args) { + if (!CheckPerfEventLimit()) { + return false; + } + static std::map<std::string, std::pair<int, std::string>> type_map = { {"hw", {PERF_TYPE_HARDWARE, "hardware events"}}, {"sw", {PERF_TYPE_SOFTWARE, "software events"}}, diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index 83f60e73..48255fad 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -191,6 +191,10 @@ class RecordCommand : public Command { }; bool RecordCommand::Run(const std::vector<std::string>& args) { + if (!CheckPerfEventLimit()) { + return false; + } + // 1. Parse options, and use default measured event type if not given. std::vector<std::string> workload_args; if (!ParseOptions(args, &workload_args)) { diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp index f477abfd..dca7ed05 100644 --- a/simpleperf/cmd_stat.cpp +++ b/simpleperf/cmd_stat.cpp @@ -101,6 +101,10 @@ class StatCommand : public Command { }; bool StatCommand::Run(const std::vector<std::string>& args) { + if (!CheckPerfEventLimit()) { + return false; + } + // 1. Parse options, and use default measured event types if not given. std::vector<std::string> workload_args; if (!ParseOptions(args, &workload_args)) { diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp index 578c1b16..798d08dc 100644 --- a/simpleperf/environment.cpp +++ b/simpleperf/environment.cpp @@ -31,6 +31,10 @@ #include <android-base/strings.h> #include <android-base/stringprintf.h> +#if defined(__ANDROID__) +#include <sys/system_properties.h> +#endif + #include "read_elf.h" #include "utils.h" @@ -385,3 +389,62 @@ 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() { + 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; +} diff --git a/simpleperf/environment.h b/simpleperf/environment.h index cb44ebe3..b8eac610 100644 --- a/simpleperf/environment.h +++ b/simpleperf/environment.h @@ -69,4 +69,6 @@ bool GetValidThreadsFromThreadString(const std::string& tid_str, std::set<pid_t> bool GetExecPath(std::string* exec_path); +bool CheckPerfEventLimit(); + #endif // SIMPLE_PERF_ENVIRONMENT_H_ |