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