1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker *
4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker *
8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker *
10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker */
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Worker #include "MapRecordReader.h"
18*288bf522SAndroid Build Coastguard Worker
19*288bf522SAndroid Build Coastguard Worker #include <stdint.h>
20*288bf522SAndroid Build Coastguard Worker #include <sys/mman.h>
21*288bf522SAndroid Build Coastguard Worker #include <sys/stat.h>
22*288bf522SAndroid Build Coastguard Worker
23*288bf522SAndroid Build Coastguard Worker #include <vector>
24*288bf522SAndroid Build Coastguard Worker
25*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
26*288bf522SAndroid Build Coastguard Worker
27*288bf522SAndroid Build Coastguard Worker #include "environment.h"
28*288bf522SAndroid Build Coastguard Worker #include "thread_tree.h"
29*288bf522SAndroid Build Coastguard Worker
30*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
31*288bf522SAndroid Build Coastguard Worker
ReadKernelMaps()32*288bf522SAndroid Build Coastguard Worker bool MapRecordReader::ReadKernelMaps() {
33*288bf522SAndroid Build Coastguard Worker KernelMmap kernel_mmap;
34*288bf522SAndroid Build Coastguard Worker std::vector<KernelMmap> module_mmaps;
35*288bf522SAndroid Build Coastguard Worker GetKernelAndModuleMmaps(&kernel_mmap, &module_mmaps);
36*288bf522SAndroid Build Coastguard Worker
37*288bf522SAndroid Build Coastguard Worker // Inject an mmap record covering all of kernel's address space. This is used to set up a map for
38*288bf522SAndroid Build Coastguard Worker // dynamically allocated BPF JIT regions outside [kernel.kallsyms]. Needs to be added first.
39*288bf522SAndroid Build Coastguard Worker MmapRecord bpf_record(attr_, true, UINT_MAX, 0, 0, std::numeric_limits<uint64_t>::max(), 0,
40*288bf522SAndroid Build Coastguard Worker DEFAULT_KERNEL_BPF_MMAP_NAME, event_id_);
41*288bf522SAndroid Build Coastguard Worker if (!callback_(&bpf_record)) {
42*288bf522SAndroid Build Coastguard Worker return false;
43*288bf522SAndroid Build Coastguard Worker }
44*288bf522SAndroid Build Coastguard Worker MmapRecord mmap_record(attr_, true, UINT_MAX, 0, kernel_mmap.start_addr, kernel_mmap.len, 0,
45*288bf522SAndroid Build Coastguard Worker kernel_mmap.filepath, event_id_);
46*288bf522SAndroid Build Coastguard Worker if (!callback_(&mmap_record)) {
47*288bf522SAndroid Build Coastguard Worker return false;
48*288bf522SAndroid Build Coastguard Worker }
49*288bf522SAndroid Build Coastguard Worker for (const auto& module_mmap : module_mmaps) {
50*288bf522SAndroid Build Coastguard Worker MmapRecord mmap_record(attr_, true, UINT_MAX, 0, module_mmap.start_addr, module_mmap.len, 0,
51*288bf522SAndroid Build Coastguard Worker module_mmap.filepath, event_id_);
52*288bf522SAndroid Build Coastguard Worker if (!callback_(&mmap_record)) {
53*288bf522SAndroid Build Coastguard Worker return false;
54*288bf522SAndroid Build Coastguard Worker }
55*288bf522SAndroid Build Coastguard Worker }
56*288bf522SAndroid Build Coastguard Worker return true;
57*288bf522SAndroid Build Coastguard Worker }
58*288bf522SAndroid Build Coastguard Worker
ReadProcessMaps(pid_t pid,uint64_t timestamp)59*288bf522SAndroid Build Coastguard Worker bool MapRecordReader::ReadProcessMaps(pid_t pid, uint64_t timestamp) {
60*288bf522SAndroid Build Coastguard Worker std::vector<pid_t> tids = GetThreadsInProcess(pid);
61*288bf522SAndroid Build Coastguard Worker return ReadProcessMaps(pid, std::unordered_set<pid_t>(tids.begin(), tids.end()), timestamp);
62*288bf522SAndroid Build Coastguard Worker }
63*288bf522SAndroid Build Coastguard Worker
ReadProcessMaps(pid_t pid,const std::unordered_set<pid_t> & tids,uint64_t timestamp)64*288bf522SAndroid Build Coastguard Worker bool MapRecordReader::ReadProcessMaps(pid_t pid, const std::unordered_set<pid_t>& tids,
65*288bf522SAndroid Build Coastguard Worker uint64_t timestamp) {
66*288bf522SAndroid Build Coastguard Worker // Dump mmap records.
67*288bf522SAndroid Build Coastguard Worker std::vector<ThreadMmap> thread_mmaps;
68*288bf522SAndroid Build Coastguard Worker if (!GetThreadMmapsInProcess(pid, &thread_mmaps)) {
69*288bf522SAndroid Build Coastguard Worker // The process may exit before we get its info.
70*288bf522SAndroid Build Coastguard Worker return true;
71*288bf522SAndroid Build Coastguard Worker }
72*288bf522SAndroid Build Coastguard Worker for (const auto& map : thread_mmaps) {
73*288bf522SAndroid Build Coastguard Worker if (!(map.prot & PROT_EXEC) && !keep_non_executable_maps_) {
74*288bf522SAndroid Build Coastguard Worker continue;
75*288bf522SAndroid Build Coastguard Worker }
76*288bf522SAndroid Build Coastguard Worker Mmap2Record record(attr_, false, pid, pid, map.start_addr, map.len, map.pgoff, map.prot,
77*288bf522SAndroid Build Coastguard Worker map.name, event_id_, timestamp);
78*288bf522SAndroid Build Coastguard Worker if (!callback_(&record)) {
79*288bf522SAndroid Build Coastguard Worker return false;
80*288bf522SAndroid Build Coastguard Worker }
81*288bf522SAndroid Build Coastguard Worker }
82*288bf522SAndroid Build Coastguard Worker // Dump process name.
83*288bf522SAndroid Build Coastguard Worker std::string process_name = GetCompleteProcessName(pid);
84*288bf522SAndroid Build Coastguard Worker if (!process_name.empty()) {
85*288bf522SAndroid Build Coastguard Worker CommRecord record(attr_, pid, pid, process_name, event_id_, timestamp);
86*288bf522SAndroid Build Coastguard Worker if (!callback_(&record)) {
87*288bf522SAndroid Build Coastguard Worker return false;
88*288bf522SAndroid Build Coastguard Worker }
89*288bf522SAndroid Build Coastguard Worker }
90*288bf522SAndroid Build Coastguard Worker // Dump thread info.
91*288bf522SAndroid Build Coastguard Worker for (const auto& tid : tids) {
92*288bf522SAndroid Build Coastguard Worker std::string name;
93*288bf522SAndroid Build Coastguard Worker if (tid != pid && GetThreadName(tid, &name)) {
94*288bf522SAndroid Build Coastguard Worker // If a thread name matches the suffix of its process name, probably the thread name
95*288bf522SAndroid Build Coastguard Worker // is stripped by TASK_COMM_LEN.
96*288bf522SAndroid Build Coastguard Worker if (android::base::EndsWith(process_name, name)) {
97*288bf522SAndroid Build Coastguard Worker name = process_name;
98*288bf522SAndroid Build Coastguard Worker }
99*288bf522SAndroid Build Coastguard Worker CommRecord comm_record(attr_, pid, tid, name, event_id_, timestamp);
100*288bf522SAndroid Build Coastguard Worker if (!callback_(&comm_record)) {
101*288bf522SAndroid Build Coastguard Worker return false;
102*288bf522SAndroid Build Coastguard Worker }
103*288bf522SAndroid Build Coastguard Worker }
104*288bf522SAndroid Build Coastguard Worker }
105*288bf522SAndroid Build Coastguard Worker return true;
106*288bf522SAndroid Build Coastguard Worker }
107*288bf522SAndroid Build Coastguard Worker
MapRecordThread(const MapRecordReader & map_record_reader)108*288bf522SAndroid Build Coastguard Worker MapRecordThread::MapRecordThread(const MapRecordReader& map_record_reader)
109*288bf522SAndroid Build Coastguard Worker : map_record_reader_(map_record_reader), fp_(nullptr, fclose) {
110*288bf522SAndroid Build Coastguard Worker map_record_reader_.SetCallback([this](Record* r) { return WriteRecordToFile(r); });
111*288bf522SAndroid Build Coastguard Worker tmpfile_ = ScopedTempFiles::CreateTempFile();
112*288bf522SAndroid Build Coastguard Worker fp_.reset(fdopen(tmpfile_->release(), "r+"));
113*288bf522SAndroid Build Coastguard Worker thread_ = std::thread([this]() { thread_result_ = RunThread(); });
114*288bf522SAndroid Build Coastguard Worker }
115*288bf522SAndroid Build Coastguard Worker
~MapRecordThread()116*288bf522SAndroid Build Coastguard Worker MapRecordThread::~MapRecordThread() {
117*288bf522SAndroid Build Coastguard Worker if (thread_.joinable()) {
118*288bf522SAndroid Build Coastguard Worker early_stop_ = true;
119*288bf522SAndroid Build Coastguard Worker thread_.join();
120*288bf522SAndroid Build Coastguard Worker }
121*288bf522SAndroid Build Coastguard Worker }
122*288bf522SAndroid Build Coastguard Worker
RunThread()123*288bf522SAndroid Build Coastguard Worker bool MapRecordThread::RunThread() {
124*288bf522SAndroid Build Coastguard Worker if (!fp_) {
125*288bf522SAndroid Build Coastguard Worker return false;
126*288bf522SAndroid Build Coastguard Worker }
127*288bf522SAndroid Build Coastguard Worker if (!map_record_reader_.ReadKernelMaps()) {
128*288bf522SAndroid Build Coastguard Worker return false;
129*288bf522SAndroid Build Coastguard Worker }
130*288bf522SAndroid Build Coastguard Worker for (auto pid : GetAllProcesses()) {
131*288bf522SAndroid Build Coastguard Worker if (early_stop_) {
132*288bf522SAndroid Build Coastguard Worker return false;
133*288bf522SAndroid Build Coastguard Worker }
134*288bf522SAndroid Build Coastguard Worker if (!map_record_reader_.ReadProcessMaps(pid, 0)) {
135*288bf522SAndroid Build Coastguard Worker return false;
136*288bf522SAndroid Build Coastguard Worker }
137*288bf522SAndroid Build Coastguard Worker }
138*288bf522SAndroid Build Coastguard Worker return true;
139*288bf522SAndroid Build Coastguard Worker }
140*288bf522SAndroid Build Coastguard Worker
WriteRecordToFile(Record * record)141*288bf522SAndroid Build Coastguard Worker bool MapRecordThread::WriteRecordToFile(Record* record) {
142*288bf522SAndroid Build Coastguard Worker if (fwrite(record->Binary(), record->size(), 1, fp_.get()) != 1) {
143*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "failed to write map records to file";
144*288bf522SAndroid Build Coastguard Worker return false;
145*288bf522SAndroid Build Coastguard Worker }
146*288bf522SAndroid Build Coastguard Worker return true;
147*288bf522SAndroid Build Coastguard Worker }
148*288bf522SAndroid Build Coastguard Worker
Join()149*288bf522SAndroid Build Coastguard Worker bool MapRecordThread::Join() {
150*288bf522SAndroid Build Coastguard Worker if (!thread_joined_) {
151*288bf522SAndroid Build Coastguard Worker thread_.join();
152*288bf522SAndroid Build Coastguard Worker thread_joined_ = true;
153*288bf522SAndroid Build Coastguard Worker if (!thread_result_) {
154*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "map record thread failed";
155*288bf522SAndroid Build Coastguard Worker }
156*288bf522SAndroid Build Coastguard Worker }
157*288bf522SAndroid Build Coastguard Worker return thread_result_;
158*288bf522SAndroid Build Coastguard Worker }
159*288bf522SAndroid Build Coastguard Worker
ReadMapRecordData(const std::function<bool (const char *,size_t)> & callback)160*288bf522SAndroid Build Coastguard Worker bool MapRecordThread::ReadMapRecordData(const std::function<bool(const char*, size_t)>& callback) {
161*288bf522SAndroid Build Coastguard Worker if (fseek(fp_.get(), 0, SEEK_END) != 0) {
162*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "fseek() failed";
163*288bf522SAndroid Build Coastguard Worker return false;
164*288bf522SAndroid Build Coastguard Worker }
165*288bf522SAndroid Build Coastguard Worker off_t offset = ftello(fp_.get());
166*288bf522SAndroid Build Coastguard Worker if (offset == -1) {
167*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "ftello() failed";
168*288bf522SAndroid Build Coastguard Worker return false;
169*288bf522SAndroid Build Coastguard Worker }
170*288bf522SAndroid Build Coastguard Worker uint64_t file_size = static_cast<uint64_t>(offset);
171*288bf522SAndroid Build Coastguard Worker if (fseek(fp_.get(), 0, SEEK_SET) != 0) {
172*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "fseek() failed";
173*288bf522SAndroid Build Coastguard Worker return false;
174*288bf522SAndroid Build Coastguard Worker }
175*288bf522SAndroid Build Coastguard Worker std::vector<char> buffer(1024 * 1024);
176*288bf522SAndroid Build Coastguard Worker uint64_t left_bytes = file_size;
177*288bf522SAndroid Build Coastguard Worker while (left_bytes > 0) {
178*288bf522SAndroid Build Coastguard Worker size_t to_read = left_bytes > buffer.size() ? buffer.size() : left_bytes;
179*288bf522SAndroid Build Coastguard Worker if (fread(buffer.data(), to_read, 1, fp_.get()) != 1) {
180*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "fread() failed";
181*288bf522SAndroid Build Coastguard Worker return false;
182*288bf522SAndroid Build Coastguard Worker }
183*288bf522SAndroid Build Coastguard Worker if (!callback(buffer.data(), to_read)) {
184*288bf522SAndroid Build Coastguard Worker return false;
185*288bf522SAndroid Build Coastguard Worker }
186*288bf522SAndroid Build Coastguard Worker left_bytes -= to_read;
187*288bf522SAndroid Build Coastguard Worker }
188*288bf522SAndroid Build Coastguard Worker return true;
189*288bf522SAndroid Build Coastguard Worker }
190*288bf522SAndroid Build Coastguard Worker
ReadMapRecords(const std::function<void (const Record *)> & callback,bool only_kernel_maps)191*288bf522SAndroid Build Coastguard Worker bool MapRecordThread::ReadMapRecords(const std::function<void(const Record*)>& callback,
192*288bf522SAndroid Build Coastguard Worker bool only_kernel_maps) {
193*288bf522SAndroid Build Coastguard Worker if (fseek(fp_.get(), 0, SEEK_END) != 0) {
194*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "fseek() failed";
195*288bf522SAndroid Build Coastguard Worker return false;
196*288bf522SAndroid Build Coastguard Worker }
197*288bf522SAndroid Build Coastguard Worker off_t offset = ftello(fp_.get());
198*288bf522SAndroid Build Coastguard Worker if (offset == -1) {
199*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "ftello() failed";
200*288bf522SAndroid Build Coastguard Worker return false;
201*288bf522SAndroid Build Coastguard Worker }
202*288bf522SAndroid Build Coastguard Worker uint64_t file_size = static_cast<uint64_t>(offset);
203*288bf522SAndroid Build Coastguard Worker if (fseek(fp_.get(), 0, SEEK_SET) != 0) {
204*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "fseek() failed";
205*288bf522SAndroid Build Coastguard Worker return false;
206*288bf522SAndroid Build Coastguard Worker }
207*288bf522SAndroid Build Coastguard Worker uint64_t nread = 0;
208*288bf522SAndroid Build Coastguard Worker std::vector<char> buffer(1024);
209*288bf522SAndroid Build Coastguard Worker while (nread < file_size) {
210*288bf522SAndroid Build Coastguard Worker if (fread(buffer.data(), Record::header_size(), 1, fp_.get()) != 1) {
211*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "fread() failed";
212*288bf522SAndroid Build Coastguard Worker return false;
213*288bf522SAndroid Build Coastguard Worker }
214*288bf522SAndroid Build Coastguard Worker RecordHeader header;
215*288bf522SAndroid Build Coastguard Worker if (!header.Parse(buffer.data())) {
216*288bf522SAndroid Build Coastguard Worker return false;
217*288bf522SAndroid Build Coastguard Worker }
218*288bf522SAndroid Build Coastguard Worker if (buffer.size() < header.size) {
219*288bf522SAndroid Build Coastguard Worker buffer.resize(header.size);
220*288bf522SAndroid Build Coastguard Worker }
221*288bf522SAndroid Build Coastguard Worker if (fread(buffer.data() + Record::header_size(), header.size - Record::header_size(), 1,
222*288bf522SAndroid Build Coastguard Worker fp_.get()) != 1) {
223*288bf522SAndroid Build Coastguard Worker PLOG(ERROR) << "fread() failed";
224*288bf522SAndroid Build Coastguard Worker return false;
225*288bf522SAndroid Build Coastguard Worker }
226*288bf522SAndroid Build Coastguard Worker auto r = ReadRecordFromBuffer(map_record_reader_.Attr(), header.type, buffer.data(),
227*288bf522SAndroid Build Coastguard Worker buffer.data() + header.size);
228*288bf522SAndroid Build Coastguard Worker CHECK(r);
229*288bf522SAndroid Build Coastguard Worker if (only_kernel_maps && !r->InKernel()) {
230*288bf522SAndroid Build Coastguard Worker break;
231*288bf522SAndroid Build Coastguard Worker }
232*288bf522SAndroid Build Coastguard Worker callback(r.get());
233*288bf522SAndroid Build Coastguard Worker nread += header.size;
234*288bf522SAndroid Build Coastguard Worker }
235*288bf522SAndroid Build Coastguard Worker return true;
236*288bf522SAndroid Build Coastguard Worker }
237*288bf522SAndroid Build Coastguard Worker
238*288bf522SAndroid Build Coastguard Worker } // namespace simpleperf
239