1 /*
2 * Copyright (C) 2021 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 "RecordFilter.h"
18
19 #include "environment.h"
20 #include "utils.h"
21
22 namespace simpleperf {
23
ParseOptions(OptionValueMap & options)24 bool RecordFilter::ParseOptions(OptionValueMap& options) {
25 for (bool exclude : {true, false}) {
26 std::string prefix = exclude ? "--exclude-" : "--include-";
27 for (const OptionValue& value : options.PullValues(prefix + "pid")) {
28 if (auto pids = GetTidsFromString(*value.str_value, false); pids) {
29 AddPids(pids.value(), exclude);
30 } else {
31 return false;
32 }
33 }
34 for (const OptionValue& value : options.PullValues(prefix + "tid")) {
35 if (auto tids = GetTidsFromString(*value.str_value, false); tids) {
36 AddTids(tids.value(), exclude);
37 } else {
38 return false;
39 }
40 }
41 for (const OptionValue& value : options.PullValues(prefix + "process-name")) {
42 AddProcessNameRegex(*value.str_value, exclude);
43 }
44 for (const OptionValue& value : options.PullValues(prefix + "thread-name")) {
45 AddThreadNameRegex(*value.str_value, exclude);
46 }
47 for (const OptionValue& value : options.PullValues(prefix + "uid")) {
48 if (auto uids = ParseUintVector<uid_t>(*value.str_value); uids) {
49 AddUids(uids.value(), exclude);
50 } else {
51 return false;
52 }
53 }
54 }
55 return true;
56 }
57
AddPids(const std::set<pid_t> & pids,bool exclude)58 void RecordFilter::AddPids(const std::set<pid_t>& pids, bool exclude) {
59 RecordFilterCondition& cond = GetCondition(exclude);
60 cond.used = true;
61 cond.pids.insert(pids.begin(), pids.end());
62 }
63
AddTids(const std::set<pid_t> & tids,bool exclude)64 void RecordFilter::AddTids(const std::set<pid_t>& tids, bool exclude) {
65 RecordFilterCondition& cond = GetCondition(exclude);
66 cond.used = true;
67 cond.tids.insert(tids.begin(), tids.end());
68 }
69
AddProcessNameRegex(const std::string & process_name,bool exclude)70 void RecordFilter::AddProcessNameRegex(const std::string& process_name, bool exclude) {
71 RecordFilterCondition& cond = GetCondition(exclude);
72 cond.used = true;
73 cond.process_name_regs.emplace_back(process_name, std::regex::optimize);
74 }
75
AddThreadNameRegex(const std::string & thread_name,bool exclude)76 void RecordFilter::AddThreadNameRegex(const std::string& thread_name, bool exclude) {
77 RecordFilterCondition& cond = GetCondition(exclude);
78 cond.used = true;
79 cond.thread_name_regs.emplace_back(thread_name, std::regex::optimize);
80 }
81
AddUids(const std::set<uid_t> & uids,bool exclude)82 void RecordFilter::AddUids(const std::set<uid_t>& uids, bool exclude) {
83 RecordFilterCondition& cond = GetCondition(exclude);
84 cond.used = true;
85 cond.uids.insert(uids.begin(), uids.end());
86 }
87
Check(const SampleRecord * r)88 bool RecordFilter::Check(const SampleRecord* r) {
89 if (exclude_condition_.used && CheckCondition(r, exclude_condition_)) {
90 return false;
91 }
92 if (include_condition_.used && !CheckCondition(r, include_condition_)) {
93 return false;
94 }
95 return true;
96 }
97
Clear()98 void RecordFilter::Clear() {
99 exclude_condition_ = RecordFilterCondition();
100 include_condition_ = RecordFilterCondition();
101 pid_to_uid_map_.clear();
102 }
103
CheckCondition(const SampleRecord * r,const RecordFilterCondition & condition)104 bool RecordFilter::CheckCondition(const SampleRecord* r, const RecordFilterCondition& condition) {
105 if (condition.pids.count(r->tid_data.pid) == 1) {
106 return true;
107 }
108 if (condition.tids.count(r->tid_data.tid) == 1) {
109 return true;
110 }
111 if (!condition.process_name_regs.empty()) {
112 if (ThreadEntry* process = thread_tree_.FindThread(r->tid_data.pid); process != nullptr) {
113 if (SearchInRegs(process->comm, condition.process_name_regs)) {
114 return true;
115 }
116 }
117 }
118 if (!condition.thread_name_regs.empty()) {
119 if (ThreadEntry* thread = thread_tree_.FindThread(r->tid_data.tid); thread != nullptr) {
120 if (SearchInRegs(thread->comm, condition.thread_name_regs)) {
121 return true;
122 }
123 }
124 }
125 if (!condition.uids.empty()) {
126 if (auto uid_value = GetUidForProcess(r->tid_data.pid); uid_value) {
127 if (condition.uids.count(uid_value.value()) == 1) {
128 return true;
129 }
130 }
131 }
132 return false;
133 }
134
SearchInRegs(const std::string & s,const std::vector<std::regex> & regs)135 bool RecordFilter::SearchInRegs(const std::string& s, const std::vector<std::regex>& regs) {
136 for (auto& reg : regs) {
137 if (std::regex_search(s, reg)) {
138 return true;
139 }
140 }
141 return false;
142 }
143
GetUidForProcess(pid_t pid)144 std::optional<uid_t> RecordFilter::GetUidForProcess(pid_t pid) {
145 if (auto it = pid_to_uid_map_.find(pid); it != pid_to_uid_map_.end()) {
146 return it->second;
147 }
148 auto uid = GetProcessUid(pid);
149 pid_to_uid_map_[pid] = uid;
150 return uid;
151 }
152
153 } // namespace simpleperf
154